Временной ряд
Данные – траты жителей Великобритании за рубежом с января 1980г. по декабрь 2016г. в миллионах £.
Чуть более свежие данные можно найти здесь: https://www.ons.gov.uk/peoplepopulationandcommunity/leisureandtourism/timeseries/gmam/ott
uk <- read.csv("UK.csv", sep = ',', stringsAsFactors = FALSE)
uk <- ts(uk$EXPEND, start = c(1980, 1), frequency = 12)
df.uk <- data.frame(seq.Date(from = as.Date("1980-01-01"), to = as.Date("2016-12-01"), by = "month"), uk)
colnames(df.uk) <- c("DATE", "EXP")
tail(uk, 24)
Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
2015 2371 2071 2548 2901 3255 3690 4442 5506 4461 3445 2365 1972
2016 2448 2523 2607 3529 3489 3969 4569 6097 5215 4030 2820 2120
plot(uk)

Тренд сначала похож на линейный, примерно в 2008 году резко меняется. Имеет смысл рассматривать только конец ряда, сославшись на то, что резкое изменение тренда связано с финансовым кризисом.
Модель не аддитивная, амплитуда сезонной компоненты не постоянна. Посмотрим, что происходит при логарифмировании.
plot(log(uk))

Амплитуда не постоянна, значит, модель не является мультипликативной.
Периодограмма
\((x_1, \ldots, x_N)\) – ряд.
Представим его в виде \(x_n = C_0 + \sum\limits_{k=1}^{[(N-1)/2]}(C_kcos(2\pi n k/N) + S_ksin(2\pi n k/N))\) (\(+ C_{N/2}(-1)^n\)), если \(N\) – четное.
Общий вид периодограммы:
\(\widetilde{П}_x^N(w) = \frac{1}{N}|\sum\limits_{n = 0}^{N - 1} e^{-2\pi iwn} x_{n + 1}|^2\), \(w \in (-1/2, 1/2)\)
Так как ряд вещественный, рассматриваем \(П_x^N(k/N) = \frac{N}{2}\begin{cases} 2C_0^2, &k = 0\\ C_k^2 + S_k^2, &0 < k < \frac{N}{2}\\ 2C_{N/2}^2, &k = \frac{N}{2} \end{cases}\)
spec.pgram(uk, detrend = FALSE, fast = FALSE, log='no', xaxt = 'n')
axis(1, at = c(0,1,2,3,4,5,6), labels = c('0', '1/12', '2/12', '3/12', '4/12', '5/12', '6/12'))

spec.pgram(uk, detrend = TRUE, fast = FALSE, log='no', xaxt = 'n')
axis(1, at = c(0,1,2,3,4,5,6), labels = c('0', '1/12', '2/12', '3/12', '4/12', '5/12', '6/12'))

Заметны периоды 12 (год), 6 (полгода), 4 (квартал), 2.4, 2 и частота близкая к нулю.
Отступление: Пример про растекание частоты
\(x_n = cos(2\pi n/10)\)
par(mfrow=c(1,2))
spec.pgram(cos(2*pi*1:92/10), detrend = FALSE, fast = FALSE, log='yes', taper=0, pad=0) #растекается
spec.pgram(cos(2*pi*1:100/10), detrend = FALSE, fast = FALSE, log='yes', taper=0, pad = 0)#не растекается

Отступление: белый шум
\(w_t, t = 0, \pm 1, \pm 2, \ldots\) – некоррелированые случайные величины, \(\mathbb{E}w_t = 0,~\sigma_w^2\), пишут, например, \(w_t \sim wn(0,~\sigma_w^2)\).
если кроме того \(w_t\) – iid, пишут \(iid(0,~\sigma_w^2)\)
если \(w_t\) – iid и \(w_t \sim N(0, ~\sigma_w^2)\), шум гауссовский
Периодограмма гауссовского шума
wn <- ts(rnorm(1000))
spec.pgram(wn, detrend = FALSE, log = 'no')

spec.pgram(wn, detrend = FALSE, log = 'yes')

Автоковариационная функция
acf(wn)

Cглаживание временного ряда и выделение тренда
Тренд – медленно меняющаяся компонента ряда.
Тренд – случайный процесс, где медленно меняющаяся компонента превалирует.
Чем отличается сглаживание от выделения тренда?
- Сглаживание даст медленно меняющуюся компоненту. Если понимать тренд как некоторую неслучайную функцию, то можем получить тренд, а можем и нет.
Линейный фильтр, FIR, причинный фильтр, АЧХ, ФЧХ
\(x_n\) – ряд.
Фильтры
\(y_j = (\Phi(X))_j = \sum\limits_{i = -\infty}^{\infty} h_i x_{j- i}\) – линейный фильтр
\(\{h_i\}\) – импульсная характеристика (impulse response)
FIR – finite impulse response, конечное число \(h_i\) ненулевые, т.е. \((\Phi(X))_j = \sum\limits_{i = -r_1}^{r_2} h_i x_{j- i}\)
Причинный фильтр (casual filter), смотрим только в “прошлое”: \((\Phi(X))_j = \sum\limits_{i = 0}^{r} h_i x_{j- i}\)
АЧХ, ФЧХ
\(H_{\Phi}(z) = \sum\limits_i h_i z^{-i}\) – передаточная функция (transfer function)
\(|H_{\Phi}(e^{i2\pi w})|\) – Амплитудно частотная характеристика (АЧХ, frequency response), показывает как меняется амплитуда в зависимости от частоты
\(\varphi_\Phi(w) = Arg H_{\Phi}(\varphi^{i2\pi w})\) – Фазочастотная характеристика (phase response)
Пример
Функция скользящего среднего
MovAvg <- function(series, M){
avg <- sapply(1:length(series), FUN = function(i){
if(M %% 2 == 0){
l <- ((i - M/2 + 1):(i-1))
r <- (i:(i + M/2))
} else{
l <- ((i - floor(M/2)):(i-1))
r <- ((i + 1):(i + floor(M/2)))
}
l <- l[l > 0]
r <- r[r <= length(series)]
h <- 1/(length(r) + length(l) + 1*(M %% 2))
if(M %% 2 == 0) sum(series[c(l,r)])*h
else sum(series[c(l, i, r)])*h
})
}
Скользящее среднее по прошлому
MovAvg.cause <- function(series, M){
avg <- sapply(1:length(series), FUN = function(i){
l <- ((i - M + 1):i)
l <- l[l > 0]
h <- 1/length(l)
sum(series[l])*h
})
}
Функция АЧХ
frequencyResponse <- function(h, w){
fr <- w
if(max(fr) > 0.5) fr <- fr / (max(w) * 2)
sapply(fr, function(freq){
cs <- exp(-(1:length(h))*1i * 2*pi* freq)
pr <- h * cs
return(abs(sum(pr)))
})
}
Пусть \(x_n = cos(2\pi\omega n)\).
Применим фильтр, получим \((\Phi(X))_n = A_{\phi}(\omega)cos(2\pi\omega n + \varphi_{\phi}(\omega))\). АЧХ фильтра – то как меняется амплитуда у косинуса с частотой \(\omega\).
В случае \(x_n = cos(2\pi\omega n)\), \(A_{\phi}(\omega) = 2sin(\pi\omega)\)
xn <- cos(2*pi* 1/12 * (1:100) + 0.5)
plot(xn, type = 'l')

Перейдем к разностям
xn.filtered <- diff(xn)
plot(xn.filtered, type = 'l')

АЧХ
h <- c(-1,1)
o <- seq(0, pi, 0.001)/2/pi
plot(frequencyResponse(h,o) ~ o, type = 'l', xlab = "frequency", ylab = "response", main = "Frequency Response")

\(A_{\phi}(\omega) = 2sin(\pi\omega)\)
plot(2*sin(pi*o) ~ o, type = 'l', xlab = "frequency", ylab = "response", main = "Frequency Response")

Роль нормы коэффициентов фильтра
- \(x_n\) – некоторый ряд
- Применили фильтр \(y = \sum\limits_{i = 1}^n a_i x_i\)
- Добавили ошибки \(x_i = x_i + \epsilon_i\), \(D(\epsilon_i) = \sigma^2\), \(\epsilon_i\) – независимы
- Тогда \(\widehat{y} = \sum\limits_{i = 1}^n a_i (x_i + \epsilon_i)\)
- \(\mathbf{E}\widehat{y} = y\), \(D\widehat{y} = \sum\limits_{i = 1}^n a_i^2 \sigma^2 = \|A\|^2\sigma^2\)
- Минимизируя норму, минимизируем дисперсию. Лучший результат при \(a_i = 1/n\)
Cкользящее среднее
Скользящее среднее – линейный фильтр, для которого \(h_i = \frac{1}{2M + 1}\).
Функция, которая строит три периодограммы сразу (для исходного ряда, результата применения фильтра и остатка)
periodogramBuilder <- function(series, filtered){
par(mfrow=c(1,3))
sp.initial <- spec.pgram(series, detrend = FALSE, fast = FALSE, log='no', taper=0)
sp.filtered <- spec.pgram(na.omit(filtered), detrend = FALSE, fast = FALSE, log='no', taper=0)
sp.difference <- spec.pgram(na.omit(series - filtered), detrend = FALSE, fast = FALSE, log='no', taper=0)
par(mfrow=c(1,1))
}
Функция, которая строит все нужные картинки сразу.
movingAverageFiltering <- function(timeSeries,m){
if( !is.ts(timeSeries)){
stop("Object given is not a ts object!")
}
par(mfrow=c(1,1))
#Initial
plot(timeSeries, type='l', lty=2, ylab = 'Rate')
h <- rep(1,(m + 1*(m%%2)))/(m + 1*(m%%2))
#average
filtered <- ts(MovAvg(timeSeries, m), start = c(1980, 1), frequency = 12)
lines(filtered, col='red')
#difference (detrended)
difference <- timeSeries - filtered
plot(difference, type = 'l')
#comparing periodograms
periodogramBuilder(timeSeries, filtered)
#Frequency response
par(mfrow=c(1,1))
sp.filtered <- spec.pgram(na.omit(filtered), detrend = FALSE, fast = FALSE, log='no', taper=0, plot = FALSE)
fr.filtered <- frequencyResponse(h, sp.filtered$freq)
plot(x = sp.filtered$freq, y = fr.filtered, type = 'l', xlab = "frequency", ylab = "response", xaxt = 'n')
axis(1, at = c(0,1,2,3,4,5,6), labels = c('0', '1/12', '2/12', '3/12', '4/12', '5/12', '6/12'))
}
Сгладим ряд. Выберем окно кратное 12, чтобы убрать сезонность.
movingAverageFiltering(uk, 12)




Вся периодика ушла в остаток. Компонента, соответствующая низкой частоте, смешалась с трендом.
По АЧХ видно, что частоты, соответствующие сезонности (1/12, 2/12 и т.д.) фильтр обращает в 0.
Увиличиваем окно
movingAverageFiltering(uk, 24)




movingAverageFiltering(uk, 36)




movingAverageFiltering(uk, 60)




Чем больше окно, тем сильнее подавляем высокие частоты, что видно по АЧХ.
Остановимся на окне 12. Каких-то серьезных улучшений бОльшие окна не дают, но зато теряется больше информации на концах ряда (получим запаздываение).
“Low-pass filter” – высокие частоты убираем, низкие оставляем.
Смещение при сглаживании фильтром скользящего среднего. Роль второй производной
Общий вид фильтра:
\[\begin{align*}
y(a) = \int_{-\delta}^{\delta} f(a + x) w(x) dx, \quad \int_{-\delta}^{\delta} w(x)dx = 1,\quad \int_{-\delta}^{\delta} x w(x)dx = 0.
\end{align*}\]
Пусть \(f\) – некоторая гладкая функция, применим к ней фильтр.
\[\begin{align*}
f(a + x) = f(a) + f'(a)x + f''(a)\frac{x^2}{2} + \ldots,\\
y(a) \approx f(a) + f'(a) 0 + \frac{f''(a)}{2} \int_{-\delta}^{\delta} x^2 w(x)dx.
\end{align*}\]
В случае скользящего среднего \(w(x) = \frac{1}{2\delta}\), следовательно, у нас всегда будет смещение \(\approx \frac{\delta^2}{3} \frac{f''(a)}{2}\).
Отступление: перерисовка и запаздывание
Перерисовка
Возникает из-за того, что нам не хватает точек справа, чтобы посчитать среднее. При добавлении новой точки среднее пересчитывается.
Последовательно добавляем последние 100 точек.
plot(y = uk, x = (1:444), type = 'l')
for(i in 100:1){
ma <- MovAvg(head(uk, -i), 12)
lines(ma, type = 'l', col = 'red', ylim = c(0, 6000), xlim = c(0, 450))
}

Запаздывание
Рассмотрим причинный фильтр, например скользящее среднее, которое считается только по “прошлому”.
plot(y = uk, x = (1:444), type = 'l')
ma.c <- MovAvg.cause(uk, 12)
ma <- MovAvg(uk, 12)
lines(ma.c, type = 'l', col = 'red', ylim = c(0, 6000), xlim = c(0, 450))
lines(ma, type = 'l', col = 'blue', ylim = c(0, 6000), xlim = c(0, 450))
legend("topleft", c("Usual", "Casual"), lty=c(1,1), lwd=c(2.5,2.5),col=c("blue","red"))

Видно, что casual фильтр “догоняет” обычное среднее только через некоторое количество точек.
Скользящая медиана
В отличие от скользяещего среднего, устойчива к аутлаерам. Но негладкая и не является оценкой м.о. для несимметричного ряда. Иногда сначала применяют скользящую медиану, а потом результат сглаживают скользящим средним.
movingMedianFiltering <- function(timeSeries,k){
if( !is.ts(timeSeries)){
stop("Object given is not a ts object!")
}
par(mfrow=c(1,1))
#Initial
plot(timeSeries, type='l', lty=2, ylab = 'Rate')
#median
filtered <- runmed(timeSeries, k)
lines(ts(filtered, start = c(1980, 1), frequency = 12 ) , col='red', type='l')
#difference (detrended)
difference <- timeSeries - filtered
plot(difference, type = 'l')
#comparing periodograms
periodogramBuilder(timeSeries, filtered)
}
movingMedianFiltering(uk, 13)



Отступление: ряд без сезонности, с аутлаерами
Рассмотрим ряд среднегодовых отклонений температуры
plot(globtemp)

spec.pgram(globtemp, detrend = FALSE, log = 'no')

spec.pgram(globtemp, detrend = TRUE, log = 'no')

Видно, что сезонности нет.
Добавим аутлаеры.
temp.w.outliers <- globtemp
set.seed(1)
out <- base::sample(1:length(globtemp), 10)
temp.w.outliers[out] <- c(3.3,-3,4,-4,5,-5,4,-4, 5, -5)
Применим скользящую медиану c маленьким окном.
plot(temp.w.outliers)
temp.med <- runmed(temp.w.outliers, 3)
lines(ts(temp.med, start = 1880, frequency = 1) , col='red', type='l')

Избавились от аутлаеров.
Разность первого порядка
df <- diff(uk)
h.df <- c(-1,1)
plot(df, type='l', main='difference')
par(mfrow=c(1,2))

sp.initial <- spec.pgram(uk, detrend = FALSE, fast = FALSE, log='no', taper=0, xaxt = 'n')
axis(1, at = c(0,1,2,3,4,5,6), labels = c('0', '1/12', '2/12', '3/12', '4/12', '5/12', '6/12'))
sp.df <- spec.pgram(na.omit(df), detrend = FALSE, fast = FALSE, log='no', taper=0, xaxt = 'n')
axis(1, at = c(0,1,2,3,4,5,6), labels = c('0', '1/12', '2/12', '3/12', '4/12', '5/12', '6/12'))
par(mfrow=c(1,1))

fr.df <- frequencyResponse(h.df, sp.df$freq/12)
plot(x = sp.df$freq, y = fr.df, type = 'l', xlab = 'frequency', ylab = 'response', xaxt = 'n')
axis(1, at = c(0,1,2,3,4,5,6), labels = c('0', '1/12', '2/12', '3/12', '4/12', '5/12', '6/12'))

“High-pass filter” – пропускает высокие частоты, низкие убирает.
Почему переход к разностям это хорошо?
Если модель нашего ряда имеет вид \(x_t = \mu_t + y_t\), где \(\mu_t\) – тренд, \(y_t\) – стационарный процесс, то при переходе к разностям получим стационарный ряд, особенно, если тренд фиксирован (например, линейный)
Увеличивем вклад высоких частот. Например, легче заметить сезонность, как на периодограмме выше.
Уберем линейный тренд (если перейдем к разностям второго порядка, то квадратичный и т.д.)
Минусы
- Увеличиваем вклад шума. Например, на периодограмме выше не ясно относить ли синус с частотой чуть больше 4/12 к сезонности или шуму.
Сглаживание и выделение тренда с помощью регрессии
Линейная регрессия
fit <- lm(df.uk$EXP ~ df.uk$DATE, df.uk)
plot(df.uk, type='l')
abline(fit, col='red')

periodogramBuilder(df.uk$EXP, fit$fitted.values)

plot(fit$residuals, type='l')

Полиномиальная регрессия
cs <- cos(2*pi*(1:length(uk))/12)
sn <- sin(2*pi*(1:length(uk))/12)
fit <- lm(EXP ~ stats::poly(df.uk$DATE, 10)
, df.uk)
plot(df.uk, type='l', ylab="EXP")
lines(y= fitted(fit), x= df.uk$DATE, col='red')

plot(fit$residuals, type='l')

periodogramBuilder(df.uk$EXP, fit$fitted.values)

Kernel Smoothing (kernel regression)
Kernel Smoothing – скользящее среднее, в котором используется весовая функция (kernel).
Cчитаем, что наш ряд имеет вид:
\[\begin{align*}
x_t = f_t + y_t,
\end{align*}\]
где
\(f_t\) – некоторая гладкая функция,
\(y_t\) – стационарный процесс. Тогда
\[\begin{align*}
\widehat{f}_t = \sum_{i = 1}^{n}w_i(t)x_i,
\end{align*}\]
где
\[\begin{align*}
w_i(t) = K(\frac{t-i}{b}) / \sum_{j = 1}^{n}K(\frac{t-j}{b}).
\end{align*}\]
Обычно \(K(z) = \frac{1}{\sqrt{2\pi}} \exp(-z^2 / 2)\).
plot(uk, type='l', ylab="EXP")
trend.sm <- ksmooth(time(uk), uk, 'normal', bandwidth = 2)
lines(trend.sm, col='red')

plot(uk - trend.sm$y)

periodogramBuilder(uk, trend.sm$y)

Nearest Neighbor Regression
Строим линейную регрессию на \(k\) ближайших соседей. Т.е. предсказываем \(x_t\) по \(\{x_{t-k/2},\ldots, x_t,\ldots, x_{t+k/2}\}\).
plot(uk, type='l', ylab="m £")
neigh.t <- knn.reg(train = time(uk), y = uk, k = 24)$pred#supsmu(time(uk), uk, span = .3)
neigh.t <- ts(neigh.t, start = c(1980, 1), frequency = 12)
lines(neigh.t, col='red')

plot(uk - neigh.t)

periodogramBuilder(uk, neigh.t)

Сравнение методов
- Линейная регрессия – подходит только для выделения линейного тренда
- Полиномиальная регрессия – не подходит для прогнозирования
- Параметрические методы плохо сработают, если не предполагается, что тренд – всегда одна и та же функция
- Nearest Neighbor Regression, Kernel Smoothing – непараметрические методы, нет ограниченности моделью
Для выделения тренда я бы выбрал Nearest Neighbor Regression или Kernel Smoothing.
Seasonal Decomposition
Хотим представить ряд в виде \(X_n = T_n + S_n + N_n\).
Будем делать все для логарифмированного ряда, так как он похож на линейную модель (амплитуда примерно одинакова). Можно заменить далее сложение на умножение, разность на деление и получить алгоритм для мультипликативной модели.
Хорошее описание алгоритма нашел здесь: http://www.abs.gov.au/websitedbs/d3310114.nsf/51c9a3d36edfd0dfca256acb00118404/c890aa8e65957397ca256ce10018c9d8!opendocument
- Начальная оценка тренда. Применяем скользящее среднее с длиной окна T, в нашем случе кратной 12.
T1 <- MovAvg(log(uk), 24)
SN1 <- log(uk) - T1
periodogramBuilder(log(uk), T1)

Получили ряд в виде \(X_n = \widetilde{T}_n + \widetilde{S_n + N_n}\)
Оценка сезонной компоненты. Сглаживаем \(\widetilde{S_n + N_n}\) с маленьким окном. Получаем \(\widetilde{S_n + N_n} = \widetilde{S}_n + \widetilde{N}_n\).
Убираем полученную сезонность из исходного ряда, получаем оценку исправленного ряда (adjusted).
S1 <- MovAvg(SN1, 2)
ADJ1 <- log(uk) - S1
periodogramBuilder(SN1, S1)

Улучшенная оценка тренда. Применяем скользящее среднее с большим окном к исправленному ряду \(X_n - \widetilde{S}_n\), получаем \(\widetilde{\widetilde{T}}_n + \widetilde{\widetilde{N}}_n\)
Отсюда второй раз оцениваем \(\widetilde{\widetilde{S_n + N_n}} = X_n - \widetilde{\widetilde{T}}_n\)
T2 <- MovAvg(ADJ1, 24)
SN2 <- log(uk) - T2
periodogramBuilder(ADJ1, T2)

- Применяем скользящее среднее с маленьким окном к \(\widetilde{\widetilde{S_n + N_n}}\), получаем \(\widetilde{\widetilde{S}}_n + \widetilde{\widetilde{\widetilde{N}}}_n\). Cнова оцениваем исправленный ряд
S2 <- MovAvg(SN2, 2)
ADJ2 <- log(uk) - S2
periodogramBuilder(SN2, S2)

- Финальная оценка тренда и шума
T3 <- MovAvg(ADJ2, 24)
N1 <- ADJ2 - T3
periodogramBuilder(ADJ2, T3)

- Получили \(X_n = \widetilde{\widetilde{T}}_n + \widetilde{\widetilde{S}}_n + \widetilde{\widetilde{\widetilde{N}}}_n\)
par(mfrow=c(4,1))
plot(log(uk), type = 'l', ylab='Original')
plot(T3, type='l', ylab='Trend')
plot(S2, type='l', ylab = 'Seasonal Component')
plot(N1, type='l', ylab='Noise')

acf(N1, lag.max = 100)

Шум белым не получился. Как видно из последних периодограмм, много периодических компонент так и не выделились в сезонную компоненту.
STL (LOESS)
Алгоритм
Inner loop
Повторяем \(n_{(i)}\) раз.
\(Y_n - T_n^{(k)}\), \(T_n^{(0)} = 0\), \(Y_n\) – исходный ряд, \(T_n^{(k)}\) – оценка тренда на шаге k внутреннего цикла
- Cycle-subseries smoothing
Каждый период длины \(n_{(p)}\) сглаживается LOESS(q), \(q = n_{(s)}, d = 1\), где \(d\) – степень полинома, \(q\) – число соседей.
Кроме того, считаем сглаженные значения для одной точки перед началом и одной точки после конца каждого периода. Это нужно для того, чтобы после применения скользящих средних на следующем шаге, осталось N точек. То есть, чтобы мы ничего не потеряли.
Получили ряд \(C_{n}^{(k + 1)}\) содержащий \(N + 2*n_{(p)}\) точек.
- Low-Pass Filtering of Smoothed Cycle-Subseries
Последовательно применяем 2 скользящих средних с длинной окна \(n_{(p)}\).
Применяем скользящее среднее с длинной окна 3.
Применяем LOESS с параметрами \(q = n_{(l)}, d = 1\).
Получили ряд \(L_n^{(k + 1)}\)
- Detrending of Smoothed Cycle-Subseries
Считаем ряд \(S_n^{(k + 1)} = C_n^{(k + 1)} - L_n^{(k + 1)}\).
Считаем ряд \(Y_n - S_n^{(k + 1)}\).
Ряд без сезонности, вычисленный на предыдущем шаге, сглаживается LOESS с \(q = n_{(t)}, d = 1\).
Получили оценку тренда \(T_n^{(k + 1)}\)
Outer Loop
Повторяем \(n_{(o)}\) раз.
Пусть мы получили оценки \(T_n, S_n\) c помощью внутреннего цикла, тогда остаток \(R_n = Y_n - T_n - S_n\).
Определим веса, которые позволят нам исключить аутлаеры.
\(h = 6 median(|R_n|)\), тогда вес в точке \(n\) \(\rho_n = B(|R_n|/h)\), где \(B\)-биквадратная весовая функция.
На следующей итерации во внутреннем цикле, на шагах 2 и 6, веса, которые присваиваются точкам в LOESS умножим на соответствующие \(\rho_n\).
Параметры
Таким образом, STL имеет 6 параметров:
- \(n_{(p)}\) – количество наблюдений в каждом цикле сезонной компоненты (период)
- \(n_{(i)}\) (inner) – число итераций внутреннего цикла
- \(n_{(o)}\) (outer) – число итераций внешнего цикла
- \(n_{(l)}\) (l.window) – сглаживающий параметр для low-pass фильтра (количество соседей в LOESS)
- \(n_{(t)}\) (t.window) – сглаживающий параметр для тренда (количество соседей в LOESS)
- \(n_{(s)}\) (s.window) – сглаживающий параметр сезонности (количество соседей в LOESS)
Другие парамаетры, доступные в функции
- t(s,l).degree – степень полинома в LOESS для соответствующих компонент (0 или 1)
Использование
Выберем следующие параметры
- s.window = 13 так как у нас годовая периодичность, и параметр должен быть нечетным
- l.window = 13 рекомендуется брать ближайшим нечетным к \(n_{(p)}\)
- outer = 0, аутлаеров нет
- inner = 2, утверждается, что достаточно и одной итерации внутреннего цикла, но для лучшей сходимости рекомендуют 2
- t.window = 23, рекомендуется брать \(n_{(t)} = [1.5 n_{(p)}/(1 - 1.5/n_{(s)})]_{odd}\)
uk.stl <- stl(uk, s.window = 13, l.window = 13, outer = 0, inner = 2, t.window = 23)
plot(uk.stl)

acf(uk.stl$time.series[,3], lag.max = 100)

Стабилизация дисперсии
Остаток после stl
rem <- uk.stl$time.series[,3]
plot(rem)

Прологорифмируем исходный ряд и снова посмотрим на остаток после выделения тренда.
uk.log <- log(uk)
uk.log.stl <- stl(uk.log, s.window = 13, l.window = 13, outer = 0, inner = 2, t.window = 23)
log.rem <- uk.log.stl$time.series[,3]
plot(log.rem)

Оценим дисперсию
Идея * Выделив тренд, получили шум с некоторой дисперсией \(\xi_n = \sigma(n)\epsilon_n\)
- Выделить тренд у \(\xi_n^2 = \sigma(n)^2\epsilon_n^2\) – все равно, что найти среднее \(\mathbf{E}\xi_n^2 = \sigma(n)^2\)
Возведем остаток в квадрат и выделим тренд скользящим средним
dif.sqr <- ts(log.rem^2)
plot(dif.sqr, type = 'l')
sigma.n.sqr <- MovAvg(dif.sqr, 24)
lines(sigma.n.sqr, col='red')
legend("topleft", c("Rem^2", "sigma(n)^2"), lty=c(1,1), lwd=c(2.5,2.5),col=c("black","red"))

Построим огибающую
noise <- ts(log.rem / sqrt(sigma.n.sqr))
plot(log.rem, type = 'l')
lines(ts(sqrt(sigma.n.sqr), start = c(1980, 1), frequency = 12), col = 'blue')
lines(ts(-sqrt(sigma.n.sqr), start = c(1980, 1), frequency = 12), col = 'blue')

Оценка шума, ее периодограмма и автоковариационная функция
plot(noise)

spec.pgram(na.omit(noise), detrend = FALSE, fast = FALSE, log='no', taper=0)

acf(noise, lag.max = 50)

LS0tCnRpdGxlOiAi0JDQvdCw0LvQuNC3INCy0YDQtdC80LXQvdC90L7Qs9C+INGA0Y/QtNCwIgphdXRob3I6ICLQktC70LDQtNC40LzQuNGAINCQ0LPQtdC10LIiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgICAgdG9jOiB5ZXMKICAgICAgdG9jX2Zsb2F0OiB5ZXMKICAgICAgdG9jX2RlcHRoOiAzCi0tLQpgYGB7ciwgZWNobz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShSc3NhKQpsaWJyYXJ5KGFzdHNhKQpsaWJyYXJ5KEZOTikKYGBgCgoj0JLRgNC10LzQtdC90L3QvtC5INGA0Y/QtAoK0JTQsNC90L3Ri9C1IC0tINGC0YDQsNGC0Ysg0LbQuNGC0LXQu9C10Lkg0JLQtdC70LjQutC+0LHRgNC40YLQsNC90LjQuCDQt9CwINGA0YPQsdC10LbQvtC8INGBINGP0L3QstCw0YDRjyAxOTgw0LMuINC/0L4g0LTQtdC60LDQsdGA0YwgMjAxNtCzLiDQsiDQvNC40LvQu9C40L7QvdCw0YUgwqMuCgrQp9GD0YLRjCDQsdC+0LvQtdC1INGB0LLQtdC20LjQtSDQtNCw0L3QvdGL0LUg0LzQvtC20L3QviDQvdCw0LnRgtC4INC30LTQtdGB0Yw6IGh0dHBzOi8vd3d3Lm9ucy5nb3YudWsvcGVvcGxlcG9wdWxhdGlvbmFuZGNvbW11bml0eS9sZWlzdXJlYW5kdG91cmlzbS90aW1lc2VyaWVzL2dtYW0vb3R0CmBgYHtyfQp1ayA8LSByZWFkLmNzdigiVUsuY3N2Iiwgc2VwID0gJywnLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCnVrIDwtIHRzKHVrJEVYUEVORCwgc3RhcnQgPSBjKDE5ODAsIDEpLCBmcmVxdWVuY3kgPSAxMikKCmRmLnVrIDwtIGRhdGEuZnJhbWUoc2VxLkRhdGUoZnJvbSA9IGFzLkRhdGUoIjE5ODAtMDEtMDEiKSwgdG8gPSBhcy5EYXRlKCIyMDE2LTEyLTAxIiksIGJ5ID0gIm1vbnRoIiksIHVrKQpjb2xuYW1lcyhkZi51aykgPC0gYygiREFURSIsICJFWFAiKQp0YWlsKHVrLCAyNCkKYGBgCmBgYHtyLCBmaWcud2lkdGg9IDEwLCBmaWcuaGVpZ2h0PSA1fQpwbG90KHVrKQpgYGAK0KLRgNC10L3QtCDRgdC90LDRh9Cw0LvQsCDQv9C+0YXQvtC2INC90LAg0LvQuNC90LXQudC90YvQuSwg0L/RgNC40LzQtdGA0L3QviDQsiAyMDA4INCz0L7QtNGDINGA0LXQt9C60L4g0LzQtdC90Y/QtdGC0YHRjy4g0JjQvNC10LXRgiDRgdC80YvRgdC7INGA0LDRgdGB0LzQsNGC0YDQuNCy0LDRgtGMINGC0L7Qu9GM0LrQviDQutC+0L3QtdGGINGA0Y/QtNCwLCDRgdC+0YHQu9Cw0LLRiNC40YHRjCDQvdCwINGC0L4sINGH0YLQviDRgNC10LfQutC+0LUg0LjQt9C80LXQvdC10L3QuNC1INGC0YDQtdC90LTQsCDRgdCy0Y/Qt9Cw0L3QviDRgSDRhNC40L3QsNC90YHQvtCy0YvQvCDQutGA0LjQt9C40YHQvtC8LgoK0JzQvtC00LXQu9GMINC90LUg0LDQtNC00LjRgtC40LLQvdCw0Y8sINCw0LzQv9C70LjRgtGD0LTQsCDRgdC10LfQvtC90L3QvtC5INC60L7QvNC/0L7QvdC10L3RgtGLINC90LUg0L/QvtGB0YLQvtGP0L3QvdCwLiDQn9C+0YHQvNC+0YLRgNC40LwsINGH0YLQviDQv9GA0L7QuNGB0YXQvtC00LjRgiDQv9GA0Lgg0LvQvtCz0LDRgNC40YTQvNC40YDQvtCy0LDQvdC40LguCgpgYGB7ciwgZmlnLndpZHRoPSAxMCwgZmlnLmhlaWdodD0gNX0KcGxvdChsb2codWspKQpgYGAKCtCQ0LzQv9C70LjRgtGD0LTQsCDQvdC1INC/0L7RgdGC0L7Rj9C90L3QsCwg0LfQvdCw0YfQuNGCLCDQvNC+0LTQtdC70Ywg0L3QtSDRj9Cy0LvRj9C10YLRgdGPINC80YPQu9GM0YLQuNC/0LvQuNC60LDRgtC40LLQvdC+0LkuIAoKI9Cf0LXRgNC40L7QtNC+0LPRgNCw0LzQvNCwCiQoeF8xLCBcbGRvdHMsIHhfTikkIC0tINGA0Y/QtC4gCgrQn9GA0LXQtNGB0YLQsNCy0LjQvCDQtdCz0L4g0LIg0LLQuNC00LUKJHhfbiA9IENfMCArIFxzdW1cbGltaXRzX3trPTF9XntbKE4tMSkvMl19KENfa2NvcygyXHBpIG4gay9OKSArIFNfa3NpbigyXHBpIG4gay9OKSkkICAoJCsgQ197Ti8yfSgtMSlebiQpLCDQtdGB0LvQuCAkTiQgLS0g0YfQtdGC0L3QvtC1LgoK0J7QsdGJ0LjQuSDQstC40LQg0L/QtdGA0LjQvtC00L7Qs9GA0LDQvNC80Ys6CgokXHdpZGV0aWxkZXvQn31feF5OKHcpID0gXGZyYWN7MX17Tn18XHN1bVxsaW1pdHNfe24gPSAwfV57TiAtIDF9IGVeey0yXHBpIGl3bn0geF97biArIDF9fF4yJCwgJHcgXGluICgtMS8yLCAxLzIpJAoK0KLQsNC6INC60LDQuiDRgNGP0LQg0LLQtdGJ0LXRgdGC0LLQtdC90L3Ri9C5LCAg0YDQsNGB0YHQvNCw0YLRgNC40LLQsNC10LwKJNCfX3heTihrL04pID0gXGZyYWN7Tn17Mn1cYmVnaW57Y2FzZXN9CjJDXzBeMiwgJmsgPSAwXFwKQ19rXjIgKyBTX2teMiwgJjAgPCBrIDwgXGZyYWN7Tn17Mn1cXAoyQ197Ti8yfV4yLCAmayA9IFxmcmFje059ezJ9ClxlbmR7Y2FzZXN9JAoKCgpgYGB7ciwgZmlnLndpZHRoPSAxMCwgZmlnLmhlaWdodD0gNX0Kc3BlYy5wZ3JhbSh1aywgZGV0cmVuZCA9IEZBTFNFLCBmYXN0ID0gRkFMU0UsIGxvZz0nbm8nLCB4YXh0ID0gJ24nKQpheGlzKDEsIGF0ID0gYygwLDEsMiwzLDQsNSw2KSwgbGFiZWxzID0gYygnMCcsICcxLzEyJywgJzIvMTInLCAnMy8xMicsICc0LzEyJywgJzUvMTInLCAnNi8xMicpKQpgYGAKYGBge3IsIGZpZy53aWR0aD0gMTAsIGZpZy5oZWlnaHQ9IDV9CnNwZWMucGdyYW0odWssIGRldHJlbmQgPSBUUlVFLCBmYXN0ID0gRkFMU0UsIGxvZz0nbm8nLCB4YXh0ID0gJ24nKQpheGlzKDEsIGF0ID0gYygwLDEsMiwzLDQsNSw2KSwgbGFiZWxzID0gYygnMCcsICcxLzEyJywgJzIvMTInLCAnMy8xMicsICc0LzEyJywgJzUvMTInLCAnNi8xMicpKQpgYGAK0JfQsNC80LXRgtC90Ysg0L/QtdGA0LjQvtC00YsgMTIgKNCz0L7QtCksIDYgKNC/0L7Qu9Cz0L7QtNCwKSwgNCAo0LrQstCw0YDRgtCw0LspLCAyLjQsIDIg0Lgg0YfQsNGB0YLQvtGC0LAg0LHQu9C40LfQutCw0Y8g0Log0L3Rg9C70Y4uCgoKIyPQntGC0YHRgtGD0L/Qu9C10L3QuNC1OiDQn9GA0LjQvNC10YAg0L/RgNC+INGA0LDRgdGC0LXQutCw0L3QuNC1INGH0LDRgdGC0L7RgtGLCgokeF9uID0gY29zKDJccGkgbi8xMCkkIApgYGB7ciwgZmlnLndpZHRoPSAxMCwgZmlnLmhlaWdodD0gNX0KcGFyKG1mcm93PWMoMSwyKSkKc3BlYy5wZ3JhbShjb3MoMipwaSoxOjkyLzEwKSwgZGV0cmVuZCA9IEZBTFNFLCBmYXN0ID0gRkFMU0UsIGxvZz0neWVzJywgdGFwZXI9MCwgcGFkPTApICPRgNCw0YHRgtC10LrQsNC10YLRgdGPCnNwZWMucGdyYW0oY29zKDIqcGkqMToxMDAvMTApLCBkZXRyZW5kID0gRkFMU0UsIGZhc3QgPSBGQUxTRSwgbG9nPSd5ZXMnLCB0YXBlcj0wLCBwYWQgPSAwKSPQvdC1INGA0LDRgdGC0LXQutCw0LXRgtGB0Y8KYGBgCgojI9Ce0YLRgdGC0YPQv9C70LXQvdC40LU6INCx0LXQu9GL0Lkg0YjRg9C8CgoqICR3X3QsIHQgPSAwLCBccG0gMSwgXHBtIDIsIFxsZG90cyQgLS0g0L3QtdC60L7RgNGA0LXQu9C40YDQvtCy0LDQvdGL0LUg0YHQu9GD0YfQsNC50L3Ri9C1INCy0LXQu9C40YfQuNC90YssICRcbWF0aGJie0V9d190ID0gMCx+XHNpZ21hX3deMiQsINC/0LjRiNGD0YIsINC90LDQv9GA0LjQvNC10YAsICR3X3QgXHNpbSB3bigwLH5cc2lnbWFfd14yKSQuCgoqINC10YHQu9C4INC60YDQvtC80LUg0YLQvtCz0L4gJHdfdCQgLS0gaWlkLCDQv9C40YjRg9GCICRpaWQoMCx+XHNpZ21hX3deMikkCgoqINC10YHQu9C4ICR3X3QkIC0tIGlpZCDQuCAkd190IFxzaW0gTigwLCB+XHNpZ21hX3deMikkLCDRiNGD0Lwg0LPQsNGD0YHRgdC+0LLRgdC60LjQuQoK0J/QtdGA0LjQvtC00L7Qs9GA0LDQvNC80LAg0LPQsNGD0YHRgdC+0LLRgdC60L7Qs9C+INGI0YPQvNCwCmBgYHtyLCBmaWcud2lkdGg9IDEwLCBmaWcuaGVpZ2h0PSA1fQp3biA8LSB0cyhybm9ybSgxMDAwKSkKc3BlYy5wZ3JhbSh3biwgZGV0cmVuZCA9IEZBTFNFLCBsb2cgPSAnbm8nKQpgYGAKCgoKCmBgYHtyLCBmaWcud2lkdGg9IDEwLCBmaWcuaGVpZ2h0PSA1fQpzcGVjLnBncmFtKHduLCBkZXRyZW5kID0gRkFMU0UsIGxvZyA9ICd5ZXMnKQpgYGAKCgoK0JDQstGC0L7QutC+0LLQsNGA0LjQsNGG0LjQvtC90L3QsNGPINGE0YPQvdC60YbQuNGPCmBgYHtyLCBmaWcud2lkdGg9IDEwLCBmaWcuaGVpZ2h0PSA1fQphY2Yod24pCmBgYAoKCgojQ9Cz0LvQsNC20LjQstCw0L3QuNC1INCy0YDQtdC80LXQvdC90L7Qs9C+INGA0Y/QtNCwINC4INCy0YvQtNC10LvQtdC90LjQtSDRgtGA0LXQvdC00LAKCtCi0YDQtdC90LQgLS0g0LzQtdC00LvQtdC90L3QviDQvNC10L3Rj9GO0YnQsNGP0YHRjyDQutC+0LzQv9C+0L3QtdC90YLQsCDRgNGP0LTQsC4KCtCi0YDQtdC90LQgLS0g0YHQu9GD0YfQsNC50L3Ri9C5INC/0YDQvtGG0LXRgdGBLCDQs9C00LUg0LzQtdC00LvQtdC90L3QviDQvNC10L3Rj9GO0YnQsNGP0YHRjyDQutC+0LzQv9C+0L3QtdC90YLQsCDQv9GA0LXQstCw0LvQuNGA0YPQtdGCLgoK0KfQtdC8INC+0YLQu9C40YfQsNC10YLRgdGPINGB0LPQu9Cw0LbQuNCy0LDQvdC40LUg0L7RgiDQstGL0LTQtdC70LXQvdC40Y8g0YLRgNC10L3QtNCwPwoKKiDQodCz0LvQsNC20LjQstCw0L3QuNC1INC00LDRgdGCINC80LXQtNC70LXQvdC90L4g0LzQtdC90Y/RjtGJ0YPRjtGB0Y8g0LrQvtC80L/QvtC90LXQvdGC0YMuINCV0YHQu9C4INC/0L7QvdC40LzQsNGC0Ywg0YLRgNC10L3QtCDQutCw0Log0L3QtdC60L7RgtC+0YDRg9GOINC90LXRgdC70YPRh9Cw0LnQvdGD0Y4g0YTRg9C90LrRhtC40Y4sINGC0L4g0LzQvtC20LXQvCDQv9C+0LvRg9GH0LjRgtGMINGC0YDQtdC90LQsINCwINC80L7QttC10Lwg0Lgg0L3QtdGCLgoKCiMj0JvQuNC90LXQudC90YvQuSDRhNC40LvRjNGC0YAsIEZJUiwg0L/RgNC40YfQuNC90L3Ri9C5INGE0LjQu9GM0YLRgCwg0JDQp9ClLCDQpNCn0KUgCiR4X24kIC0tINGA0Y/QtC4KCtCk0LjQu9GM0YLRgNGLCgoqICR5X2ogPSAoXFBoaShYKSlfaiA9IFxzdW1cbGltaXRzX3tpID0gLVxpbmZ0eX1ee1xpbmZ0eX0gaF9pIHhfe2otIGl9JCAtLSDQu9C40L3QtdC50L3Ri9C5INGE0LjQu9GM0YLRgAoKKiAkXHtoX2lcfSQgLS0g0LjQvNC/0YPQu9GM0YHQvdCw0Y8g0YXQsNGA0LDQutGC0LXRgNC40YHRgtC40LrQsCAoaW1wdWxzZSByZXNwb25zZSkKCiogRklSIC0tIGZpbml0ZSBpbXB1bHNlIHJlc3BvbnNlLCDQutC+0L3QtdGH0L3QvtC1INGH0LjRgdC70L4gJGhfaSQg0L3QtdC90YPQu9C10LLRi9C1LCDRgi7QtS4gJChcUGhpKFgpKV9qID0gXHN1bVxsaW1pdHNfe2kgPSAtcl8xfV57cl8yfSBoX2kgeF97ai0gaX0kCgoqINCf0YDQuNGH0LjQvdC90YvQuSDRhNC40LvRjNGC0YAgKGNhc3VhbCBmaWx0ZXIpLCDRgdC80L7RgtGA0LjQvCDRgtC+0LvRjNC60L4g0LIgItC/0YDQvtGI0LvQvtC1IjogJChcUGhpKFgpKV9qID0gXHN1bVxsaW1pdHNfe2kgPSAwfV57cn0gaF9pIHhfe2otIGl9JAoK0JDQp9ClLCDQpNCn0KUKCiogJEhfe1xQaGl9KHopID0gXHN1bVxsaW1pdHNfaSBoX2kgel57LWl9JCAtLSDQv9C10YDQtdC00LDRgtC+0YfQvdCw0Y8g0YTRg9C90LrRhtC40Y8gKHRyYW5zZmVyIGZ1bmN0aW9uKQoKKiAkfEhfe1xQaGl9KGVee2kyXHBpIHd9KXwkIC0tINCQ0LzQv9C70LjRgtGD0LTQvdC+INGH0LDRgdGC0L7RgtC90LDRjyDRhdCw0YDQsNC60YLQtdGA0LjRgdGC0LjQutCwICjQkNCn0KUsIGZyZXF1ZW5jeSByZXNwb25zZSksINC/0L7QutCw0LfRi9Cy0LDQtdGCINC60LDQuiDQvNC10L3Rj9C10YLRgdGPINCw0LzQv9C70LjRgtGD0LTQsCDQsiDQt9Cw0LLQuNGB0LjQvNC+0YHRgtC4INC+0YIg0YfQsNGB0YLQvtGC0YsKCiogJFx2YXJwaGlfXFBoaSh3KSA9IEFyZyBIX3tcUGhpfShcdmFycGhpXntpMlxwaSB3fSkkIC0tINCk0LDQt9C+0YfQsNGB0YLQvtGC0L3QsNGPINGF0LDRgNCw0LrRgtC10YDQuNGB0YLQuNC60LAgKHBoYXNlIHJlc3BvbnNlKQoKIyMj0J/RgNC40LzQtdGACgrQpNGD0L3QutGG0LjRjyDRgdC60L7Qu9GM0LfRj9GJ0LXQs9C+INGB0YDQtdC00L3QtdCz0L4KYGBge3J9Ck1vdkF2ZyA8LSBmdW5jdGlvbihzZXJpZXMsIE0pewogIGF2ZyA8LSBzYXBwbHkoMTpsZW5ndGgoc2VyaWVzKSwgRlVOID0gZnVuY3Rpb24oaSl7CiAgICBpZihNICUlIDIgPT0gMCl7CiAgICAgIGwgPC0gKChpIC0gTS8yICsgMSk6KGktMSkpCiAgICAgIHIgPC0gKGk6KGkgKyBNLzIpKQogICAgfSBlbHNlewogICAgICAgbCA8LSAoKGkgLSBmbG9vcihNLzIpKTooaS0xKSkKICAgICAgciA8LSAoKGkgKyAxKTooaSArIGZsb29yKE0vMikpKQogICAgfQogICAgCiAgICBsIDwtIGxbbCA+IDBdCiAgICByIDwtIHJbciA8PSBsZW5ndGgoc2VyaWVzKV0gCiAgICBoIDwtIDEvKGxlbmd0aChyKSArIGxlbmd0aChsKSArIDEqKE0gJSUgMikpCiAgICBpZihNICUlIDIgPT0gMCkgc3VtKHNlcmllc1tjKGwscildKSpoIAogICAgZWxzZSBzdW0oc2VyaWVzW2MobCwgaSwgcildKSpoCiAgfSkKfQpgYGAKCtCh0LrQvtC70YzQt9GP0YnQtdC1INGB0YDQtdC00L3QtdC1INC/0L4g0L/RgNC+0YjQu9C+0LzRgwpgYGB7cn0KTW92QXZnLmNhdXNlIDwtIGZ1bmN0aW9uKHNlcmllcywgTSl7CiAgYXZnIDwtIHNhcHBseSgxOmxlbmd0aChzZXJpZXMpLCBGVU4gPSBmdW5jdGlvbihpKXsKICAgIGwgPC0gKChpIC0gTSArIDEpOmkpCiAgICBsIDwtIGxbbCA+IDBdCiAgICBoIDwtIDEvbGVuZ3RoKGwpCiAgICBzdW0oc2VyaWVzW2xdKSpoIAogIH0pCn0KYGBgCgrQpNGD0L3QutGG0LjRjyDQkNCn0KUKYGBge3J9CmZyZXF1ZW5jeVJlc3BvbnNlIDwtIGZ1bmN0aW9uKGgsIHcpewogIGZyIDwtIHcKICBpZihtYXgoZnIpID4gMC41KSBmciA8LSBmciAvIChtYXgodykgKiAyKQogIHNhcHBseShmciwgZnVuY3Rpb24oZnJlcSl7CiAgICBjcyA8LSBleHAoLSgxOmxlbmd0aChoKSkqMWkgKiAyKnBpKiBmcmVxKQogICAgcHIgPC0gaCAqIGNzCiAgICByZXR1cm4oYWJzKHN1bShwcikpKQogIH0pCn0KYGBgCgoK0J/Rg9GB0YLRjCAkeF9uID0gY29zKDJccGlcb21lZ2EgbikkLiAKCtCf0YDQuNC80LXQvdC40Lwg0YTQuNC70YzRgtGALCDQv9C+0LvRg9GH0LjQvCAkKFxQaGkoWCkpX24gPSBBX3tccGhpfShcb21lZ2EpY29zKDJccGlcb21lZ2EgbiArIFx2YXJwaGlfe1xwaGl9KFxvbWVnYSkpJC4g0JDQp9ClINGE0LjQu9GM0YLRgNCwIC0tINGC0L4g0LrQsNC6INC80LXQvdGP0LXRgtGB0Y8g0LDQvNC/0LvQuNGC0YPQtNCwINGDINC60L7RgdC40L3Rg9GB0LAg0YEg0YfQsNGB0YLQvtGC0L7QuSAkXG9tZWdhJC4gCgrQkiDRgdC70YPRh9Cw0LUgJHhfbiA9IGNvcygyXHBpXG9tZWdhIG4pJCwgJEFfe1xwaGl9KFxvbWVnYSkgPSAyc2luKFxwaVxvbWVnYSkkCmBgYHtyfQp4biA8LSBjb3MoMipwaSogMS8xMiAqICgxOjEwMCkgKyAwLjUpCnBsb3QoeG4sIHR5cGUgPSAnbCcpCmBgYAoK0J/QtdGA0LXQudC00LXQvCDQuiDRgNCw0LfQvdC+0YHRgtGP0LwKYGBge3J9CnhuLmZpbHRlcmVkIDwtIGRpZmYoeG4pCnBsb3QoeG4uZmlsdGVyZWQsIHR5cGUgPSAnbCcpCmBgYAoK0JDQp9ClCmBgYHtyfQpoIDwtICBjKC0xLDEpCm8gPC0gIHNlcSgwLCBwaSwgMC4wMDEpLzIvcGkKcGxvdChmcmVxdWVuY3lSZXNwb25zZShoLG8pIH4gbywgdHlwZSA9ICdsJywgeGxhYiA9ICJmcmVxdWVuY3kiLCB5bGFiID0gInJlc3BvbnNlIiwgbWFpbiA9ICJGcmVxdWVuY3kgUmVzcG9uc2UiKQpgYGAKCgokQV97XHBoaX0oXG9tZWdhKSA9IDJzaW4oXHBpXG9tZWdhKSQKYGBge3J9CnBsb3QoMipzaW4ocGkqbykgfiBvLCB0eXBlID0gJ2wnLCB4bGFiID0gImZyZXF1ZW5jeSIsIHlsYWIgPSAicmVzcG9uc2UiLCBtYWluID0gIkZyZXF1ZW5jeSBSZXNwb25zZSIpCmBgYAoKIyMj0KDQvtC70Ywg0L3QvtGA0LzRiyDQutC+0Y3RhNGE0LjRhtC40LXQvdGC0L7QsiDRhNC40LvRjNGC0YDQsAoKKiAkeF9uJCAtLSDQvdC10LrQvtGC0L7RgNGL0Lkg0YDRj9C0Ciog0J/RgNC40LzQtdC90LjQu9C4INGE0LjQu9GM0YLRgCAkeSA9IFxzdW1cbGltaXRzX3tpID0gMX1ebiBhX2kgeF9pJAoqINCU0L7QsdCw0LLQuNC70Lgg0L7RiNC40LHQutC4ICR4X2kgPSB4X2kgKyBcZXBzaWxvbl9pJCwgJEQoXGVwc2lsb25faSkgPSBcc2lnbWFeMiQsICRcZXBzaWxvbl9pJCAtLSDQvdC10LfQsNCy0LjRgdC40LzRiwoqINCi0L7Qs9C00LAgJFx3aWRlaGF0e3l9ID0gXHN1bVxsaW1pdHNfe2kgPSAxfV5uIGFfaSAoeF9pICsgXGVwc2lsb25faSkkCiogJFxtYXRoYmZ7RX1cd2lkZWhhdHt5fSA9IHkkLCAkRFx3aWRlaGF0e3l9ID0gXHN1bVxsaW1pdHNfe2kgPSAxfV5uIGFfaV4yIFxzaWdtYV4yID0gXHxBXHxeMlxzaWdtYV4yJAoqINCc0LjQvdC40LzQuNC30LjRgNGD0Y8g0L3QvtGA0LzRgywg0LzQuNC90LjQvNC40LfQuNGA0YPQtdC8INC00LjRgdC/0LXRgNGB0LjRji4g0JvRg9GH0YjQuNC5INGA0LXQt9GD0LvRjNGC0LDRgiDQv9GA0LggJGFfaSA9IDEvbiQKCgojI0PQutC+0LvRjNC30Y/RidC10LUg0YHRgNC10LTQvdC10LUKCtCh0LrQvtC70YzQt9GP0YnQtdC1INGB0YDQtdC00L3QtdC1IC0tINC70LjQvdC10LnQvdGL0Lkg0YTQuNC70YzRgtGALCDQtNC70Y8g0LrQvtGC0L7RgNC+0LPQviAkaF9pID0gXGZyYWN7MX17Mk0gKyAxfSQuCgrQpNGD0L3QutGG0LjRjywg0LrQvtGC0L7RgNCw0Y8g0YHRgtGA0L7QuNGCINGC0YDQuCDQv9C10YDQuNC+0LTQvtCz0YDQsNC80LzRiyDRgdGA0LDQt9GDICjQtNC70Y8g0LjRgdGF0L7QtNC90L7Qs9C+INGA0Y/QtNCwLCDRgNC10LfRg9C70YzRgtCw0YLQsCDQv9GA0LjQvNC10L3QtdC90LjRjyDRhNC40LvRjNGC0YDQsCDQuCDQvtGB0YLQsNGC0LrQsCkKYGBge3J9CnBlcmlvZG9ncmFtQnVpbGRlciA8LSBmdW5jdGlvbihzZXJpZXMsIGZpbHRlcmVkKXsKICAgcGFyKG1mcm93PWMoMSwzKSkKICAgCiAgIHNwLmluaXRpYWwgPC0gc3BlYy5wZ3JhbShzZXJpZXMsIGRldHJlbmQgPSBGQUxTRSwgZmFzdCA9IEZBTFNFLCBsb2c9J25vJywgdGFwZXI9MCkKICAgc3AuZmlsdGVyZWQgPC0gc3BlYy5wZ3JhbShuYS5vbWl0KGZpbHRlcmVkKSwgZGV0cmVuZCA9IEZBTFNFLCBmYXN0ID0gRkFMU0UsIGxvZz0nbm8nLCB0YXBlcj0wKQogICBzcC5kaWZmZXJlbmNlIDwtIHNwZWMucGdyYW0obmEub21pdChzZXJpZXMgLSBmaWx0ZXJlZCksIGRldHJlbmQgPSBGQUxTRSwgZmFzdCA9IEZBTFNFLCBsb2c9J25vJywgdGFwZXI9MCkKICAgcGFyKG1mcm93PWMoMSwxKSkKfQpgYGAKCtCk0YPQvdC60YbQuNGPLCDQutC+0YLQvtGA0LDRjyDRgdGC0YDQvtC40YIg0LLRgdC1INC90YPQttC90YvQtSDQutCw0YDRgtC40L3QutC4INGB0YDQsNC30YMuCmBgYHtyfQptb3ZpbmdBdmVyYWdlRmlsdGVyaW5nIDwtIGZ1bmN0aW9uKHRpbWVTZXJpZXMsbSl7CiAgaWYoICFpcy50cyh0aW1lU2VyaWVzKSl7CiAgICBzdG9wKCJPYmplY3QgZ2l2ZW4gaXMgbm90IGEgdHMgb2JqZWN0ISIpCiAgfQogIAogIHBhcihtZnJvdz1jKDEsMSkpCiAgI0luaXRpYWwKICBwbG90KHRpbWVTZXJpZXMsIHR5cGU9J2wnLCBsdHk9MiwgeWxhYiA9ICdSYXRlJykKICAKICBoIDwtIHJlcCgxLChtICsgMSoobSUlMikpKS8obSArIDEqKG0lJTIpKQogIAogICNhdmVyYWdlCiAgZmlsdGVyZWQgPC0gdHMoTW92QXZnKHRpbWVTZXJpZXMsIG0pLCBzdGFydCA9IGMoMTk4MCwgMSksIGZyZXF1ZW5jeSA9IDEyKSAKICBsaW5lcyhmaWx0ZXJlZCwgY29sPSdyZWQnKQogICNkaWZmZXJlbmNlIChkZXRyZW5kZWQpCiAgZGlmZmVyZW5jZSA8LSB0aW1lU2VyaWVzIC0gZmlsdGVyZWQKICBwbG90KGRpZmZlcmVuY2UsIHR5cGUgPSAnbCcpCiAgCiAgI2NvbXBhcmluZyBwZXJpb2RvZ3JhbXMKICBwZXJpb2RvZ3JhbUJ1aWxkZXIodGltZVNlcmllcywgZmlsdGVyZWQpCgogICNGcmVxdWVuY3kgcmVzcG9uc2UKICBwYXIobWZyb3c9YygxLDEpKQogIHNwLmZpbHRlcmVkIDwtIHNwZWMucGdyYW0obmEub21pdChmaWx0ZXJlZCksIGRldHJlbmQgPSBGQUxTRSwgZmFzdCA9IEZBTFNFLCBsb2c9J25vJywgdGFwZXI9MCwgcGxvdCA9IEZBTFNFKQogIGZyLmZpbHRlcmVkIDwtIGZyZXF1ZW5jeVJlc3BvbnNlKGgsIHNwLmZpbHRlcmVkJGZyZXEpCiAgcGxvdCh4ID0gc3AuZmlsdGVyZWQkZnJlcSwgeSA9IGZyLmZpbHRlcmVkLCB0eXBlID0gJ2wnLCB4bGFiID0gImZyZXF1ZW5jeSIsIHlsYWIgPSAicmVzcG9uc2UiLCB4YXh0ID0gJ24nKQogIGF4aXMoMSwgYXQgPSBjKDAsMSwyLDMsNCw1LDYpLCBsYWJlbHMgPSBjKCcwJywgJzEvMTInLCAnMi8xMicsICczLzEyJywgJzQvMTInLCAnNS8xMicsICc2LzEyJykpCn0KYGBgCgrQodCz0LvQsNC00LjQvCDRgNGP0LQuINCS0YvQsdC10YDQtdC8INC+0LrQvdC+INC60YDQsNGC0L3QvtC1IDEyLCDRh9GC0L7QsdGLINGD0LHRgNCw0YLRjCDRgdC10LfQvtC90L3QvtGB0YLRjC4KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD01fQptb3ZpbmdBdmVyYWdlRmlsdGVyaW5nKHVrLCAxMikKYGBgCtCS0YHRjyDQv9C10YDQuNC+0LTQuNC60LAg0YPRiNC70LAg0LIg0L7RgdGC0LDRgtC+0LouINCa0L7QvNC/0L7QvdC10L3RgtCwLCDRgdC+0L7RgtCy0LXRgtGB0YLQstGD0Y7RidCw0Y8g0L3QuNC30LrQvtC5INGH0LDRgdGC0L7RgtC1LCDRgdC80LXRiNCw0LvQsNGB0Ywg0YEg0YLRgNC10L3QtNC+0LwuCgrQn9C+INCQ0KfQpSDQstC40LTQvdC+LCDRh9GC0L4g0YfQsNGB0YLQvtGC0YssINGB0L7QvtGC0LLQtdGC0YHRgtCy0YPRjtGJ0LjQtSDRgdC10LfQvtC90L3QvtGB0YLQuCAoMS8xMiwgMi8xMiDQuCDRgi7QtC4pINGE0LjQu9GM0YLRgCDQvtCx0YDQsNGJ0LDQtdGCINCyIDAuCgrQo9Cy0LjQu9C40YfQuNCy0LDQtdC8INC+0LrQvdC+CmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NX0KbW92aW5nQXZlcmFnZUZpbHRlcmluZyh1aywgMjQpCm1vdmluZ0F2ZXJhZ2VGaWx0ZXJpbmcodWssIDM2KQptb3ZpbmdBdmVyYWdlRmlsdGVyaW5nKHVrLCA2MCkKYGBgCtCn0LXQvCDQsdC+0LvRjNGI0LUg0L7QutC90L4sINGC0LXQvCDRgdC40LvRjNC90LXQtSDQv9C+0LTQsNCy0LvRj9C10Lwg0LLRi9GB0L7QutC40LUg0YfQsNGB0YLQvtGC0YssINGH0YLQviDQstC40LTQvdC+INC/0L4g0JDQp9ClLgoK0J7RgdGC0LDQvdC+0LLQuNC80YHRjyDQvdCwINC+0LrQvdC1IDEyLiDQmtCw0LrQuNGFLdGC0L4g0YHQtdGA0YzQtdC30L3Ri9GFINGD0LvRg9GH0YjQtdC90LjQuSDQsdCe0LvRjNGI0LjQtSDQvtC60L3QsCDQvdC1INC00LDRjtGCLCDQvdC+INC30LDRgtC+INGC0LXRgNGP0LXRgtGB0Y8g0LHQvtC70YzRiNC1INC40L3RhNC+0YDQvNCw0YbQuNC4INC90LAg0LrQvtC90YbQsNGFINGA0Y/QtNCwICjQv9C+0LvRg9GH0LjQvCDQt9Cw0L/QsNC30LTRi9Cy0LDQtdC90LjQtSkuCgoiTG93LXBhc3MgZmlsdGVyIiAtLSDQstGL0YHQvtC60LjQtSDRh9Cw0YHRgtC+0YLRiyDRg9Cx0LjRgNCw0LXQvCwg0L3QuNC30LrQuNC1INC+0YHRgtCw0LLQu9GP0LXQvC4KCiMj0KHQvNC10YnQtdC90LjQtSDQv9GA0Lgg0YHQs9C70LDQttC40LLQsNC90LjQuCDRhNC40LvRjNGC0YDQvtC8INGB0LrQvtC70YzQt9GP0YnQtdCz0L4g0YHRgNC10LTQvdC10LPQvi4g0KDQvtC70Ywg0LLRgtC+0YDQvtC5INC/0YDQvtC40LfQstC+0LTQvdC+0LkKCtCe0LHRidC40Lkg0LLQuNC0INGE0LjQu9GM0YLRgNCwOgpcYmVnaW57YWxpZ24qfQogIHkoYSkgPSBcaW50X3stXGRlbHRhfV57XGRlbHRhfSBmKGEgKyB4KSB3KHgpIGR4LCBccXVhZCBcaW50X3stXGRlbHRhfV57XGRlbHRhfSB3KHgpZHggPSAxLFxxdWFkIFxpbnRfey1cZGVsdGF9XntcZGVsdGF9IHggdyh4KWR4ID0gMC4gClxlbmR7YWxpZ24qfQoK0J/Rg9GB0YLRjCAkZiQgLS0g0L3QtdC60L7RgtC+0YDQsNGPINCz0LvQsNC00LrQsNGPINGE0YPQvdC60YbQuNGPLCDQv9GA0LjQvNC10L3QuNC8INC6INC90LXQuSDRhNC40LvRjNGC0YAuCgpcYmVnaW57YWxpZ24qfQogIGYoYSArIHgpID0gZihhKSArIGYnKGEpeCArIGYnJyhhKVxmcmFje3heMn17Mn0gKyBcbGRvdHMsXFwKICB5KGEpIFxhcHByb3ggZihhKSArIGYnKGEpIDAgKyBcZnJhY3tmJycoYSl9ezJ9IFxpbnRfey1cZGVsdGF9XntcZGVsdGF9IHheMiB3KHgpZHguClxlbmR7YWxpZ24qfQoK0JIg0YHQu9GD0YfQsNC1INGB0LrQvtC70YzQt9GP0YnQtdCz0L4g0YHRgNC10LTQvdC10LPQviAkdyh4KSA9IFxmcmFjezF9ezJcZGVsdGF9JCwg0YHQu9C10LTQvtCy0LDRgtC10LvRjNC90L4sINGDINC90LDRgSDQstGB0LXQs9C00LAg0LHRg9C00LXRgiDRgdC80LXRidC10L3QuNC1ICRcYXBwcm94IFxmcmFje1xkZWx0YV4yfXszfSBcZnJhY3tmJycoYSl9ezJ9JC4gCgojI9Ce0YLRgdGC0YPQv9C70LXQvdC40LU6INC/0LXRgNC10YDQuNGB0L7QstC60LAg0Lgg0LfQsNC/0LDQt9C00YvQstCw0L3QuNC1CtCf0LXRgNC10YDQuNGB0L7QstC60LAKCtCS0L7Qt9C90LjQutCw0LXRgiDQuNC3LdC30LAg0YLQvtCz0L4sINGH0YLQviDQvdCw0Lwg0L3QtSDRhdCy0LDRgtCw0LXRgiDRgtC+0YfQtdC6INGB0L/RgNCw0LLQsCwg0YfRgtC+0LHRiyDQv9C+0YHRh9C40YLQsNGC0Ywg0YHRgNC10LTQvdC10LUuINCf0YDQuCDQtNC+0LHQsNCy0LvQtdC90LjQuCDQvdC+0LLQvtC5INGC0L7Rh9C60Lgg0YHRgNC10LTQvdC10LUg0L/QtdGA0LXRgdGH0LjRgtGL0LLQsNC10YLRgdGPLgoKCtCf0L7RgdC70LXQtNC+0LLQsNGC0LXQu9GM0L3QviDQtNC+0LHQsNCy0LvRj9C10Lwg0L/QvtGB0LvQtdC00L3QuNC1IDEwMCDRgtC+0YfQtdC6LgpgYGB7cn0KcGxvdCh5ID0gdWssIHggPSAoMTo0NDQpLCB0eXBlID0gJ2wnKQpmb3IoaSBpbiAxMDA6MSl7CiAgbWEgPC0gTW92QXZnKGhlYWQodWssIC1pKSwgMTIpCiAgbGluZXMobWEsIHR5cGUgPSAnbCcsIGNvbCA9ICdyZWQnLCB5bGltID0gYygwLCA2MDAwKSwgeGxpbSA9IGMoMCwgNDUwKSkKfQpgYGAKCtCX0LDQv9Cw0LfQtNGL0LLQsNC90LjQtQoK0KDQsNGB0YHQvNC+0YLRgNC40Lwg0L/RgNC40YfQuNC90L3Ri9C5INGE0LjQu9GM0YLRgCwg0L3QsNC/0YDQuNC80LXRgCDRgdC60L7Qu9GM0LfRj9GJ0LXQtSDRgdGA0LXQtNC90LXQtSwg0LrQvtGC0L7RgNC+0LUg0YHRh9C40YLQsNC10YLRgdGPINGC0L7Qu9GM0LrQviDQv9C+ICLQv9GA0L7RiNC70L7QvNGDIi4KCmBgYHtyfQpwbG90KHkgPSB1aywgeCA9ICgxOjQ0NCksIHR5cGUgPSAnbCcpCm1hLmMgPC0gTW92QXZnLmNhdXNlKHVrLCAxMikKbWEgPC0gTW92QXZnKHVrLCAxMikKbGluZXMobWEuYywgdHlwZSA9ICdsJywgY29sID0gJ3JlZCcsIHlsaW0gPSBjKDAsIDYwMDApLCB4bGltID0gYygwLCA0NTApKQpsaW5lcyhtYSwgdHlwZSA9ICdsJywgY29sID0gJ2JsdWUnLCB5bGltID0gYygwLCA2MDAwKSwgeGxpbSA9IGMoMCwgNDUwKSkKbGVnZW5kKCJ0b3BsZWZ0IiwgYygiVXN1YWwiLCAiQ2FzdWFsIiksIGx0eT1jKDEsMSksIGx3ZD1jKDIuNSwyLjUpLGNvbD1jKCJibHVlIiwicmVkIikpCmBgYArQktC40LTQvdC+LCDRh9GC0L4gY2FzdWFsINGE0LjQu9GM0YLRgCAi0LTQvtCz0L7QvdGP0LXRgiIg0L7QsdGL0YfQvdC+0LUg0YHRgNC10LTQvdC10LUg0YLQvtC70YzQutC+INGH0LXRgNC10LcgINC90LXQutC+0YLQvtGA0L7QtSDQutC+0LvQuNGH0LXRgdGC0LLQviDRgtC+0YfQtdC6LgoKCgojI9Ch0LrQvtC70YzQt9GP0YnQsNGPINC80LXQtNC40LDQvdCwCgrQkiDQvtGC0LvQuNGH0LjQtSDQvtGCINGB0LrQvtC70YzQt9GP0LXRidC10LPQviDRgdGA0LXQtNC90LXQs9C+LCDRg9GB0YLQvtC50YfQuNCy0LAg0Log0LDRg9GC0LvQsNC10YDQsNC8LiDQndC+INC90LXQs9C70LDQtNC60LDRjyDQuCDQvdC1INGP0LLQu9GP0LXRgtGB0Y8g0L7RhtC10L3QutC+0Lkg0Lwu0L4uINC00LvRjyDQvdC10YHQuNC80LzQtdGC0YDQuNGH0L3QvtCz0L4g0YDRj9C00LAuINCY0L3QvtCz0LTQsCDRgdC90LDRh9Cw0LvQsCDQv9GA0LjQvNC10L3Rj9GO0YIg0YHQutC+0LvRjNC30Y/RidGD0Y4g0LzQtdC00LjQsNC90YMsINCwINC/0L7RgtC+0Lwg0YDQtdC30YPQu9GM0YLQsNGCINGB0LPQu9Cw0LbQuNCy0LDRjtGCINGB0LrQvtC70YzQt9GP0YnQuNC8INGB0YDQtdC00L3QuNC8LiAKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NX0KbW92aW5nTWVkaWFuRmlsdGVyaW5nIDwtIGZ1bmN0aW9uKHRpbWVTZXJpZXMsayl7CiAgaWYoICFpcy50cyh0aW1lU2VyaWVzKSl7CiAgICBzdG9wKCJPYmplY3QgZ2l2ZW4gaXMgbm90IGEgdHMgb2JqZWN0ISIpCiAgfQogIAogIHBhcihtZnJvdz1jKDEsMSkpCiAgI0luaXRpYWwKICBwbG90KHRpbWVTZXJpZXMsIHR5cGU9J2wnLCBsdHk9MiwgeWxhYiA9ICdSYXRlJykKICAjbWVkaWFuCiAgZmlsdGVyZWQgPC0gcnVubWVkKHRpbWVTZXJpZXMsIGspCiAgbGluZXModHMoZmlsdGVyZWQsIHN0YXJ0ID0gYygxOTgwLCAxKSwgZnJlcXVlbmN5ID0gMTIgKSAsIGNvbD0ncmVkJywgdHlwZT0nbCcpCiAgI2RpZmZlcmVuY2UgKGRldHJlbmRlZCkKICBkaWZmZXJlbmNlIDwtIHRpbWVTZXJpZXMgLSBmaWx0ZXJlZAogIHBsb3QoZGlmZmVyZW5jZSwgdHlwZSA9ICdsJykKICAKICAjY29tcGFyaW5nIHBlcmlvZG9ncmFtcwogIAogIHBlcmlvZG9ncmFtQnVpbGRlcih0aW1lU2VyaWVzLCBmaWx0ZXJlZCkKfQoKCm1vdmluZ01lZGlhbkZpbHRlcmluZyh1aywgMTMpCmBgYAoKIyMj0J7RgtGB0YLRg9C/0LvQtdC90LjQtTog0YDRj9C0INCx0LXQtyDRgdC10LfQvtC90L3QvtGB0YLQuCwg0YEg0LDRg9GC0LvQsNC10YDQsNC80LgKCtCg0LDRgdGB0LzQvtGC0YDQuNC8INGA0Y/QtCDRgdGA0LXQtNC90LXQs9C+0LTQvtCy0YvRhSDQvtGC0LrQu9C+0L3QtdC90LjQuSDRgtC10LzQv9C10YDQsNGC0YPRgNGLCmBgYHtyfQpwbG90KGdsb2J0ZW1wKQpzcGVjLnBncmFtKGdsb2J0ZW1wLCBkZXRyZW5kID0gRkFMU0UsIGxvZyA9ICdubycpCnNwZWMucGdyYW0oZ2xvYnRlbXAsIGRldHJlbmQgPSBUUlVFLCBsb2cgPSAnbm8nKQpgYGAK0JLQuNC00L3Qviwg0YfRgtC+INGB0LXQt9C+0L3QvdC+0YHRgtC4INC90LXRgi4KCtCU0L7QsdCw0LLQuNC8INCw0YPRgtC70LDQtdGA0YsuCmBgYHtyfQp0ZW1wLncub3V0bGllcnMgPC0gZ2xvYnRlbXAKc2V0LnNlZWQoMSkKb3V0IDwtIGJhc2U6OnNhbXBsZSgxOmxlbmd0aChnbG9idGVtcCksIDEwKQp0ZW1wLncub3V0bGllcnNbb3V0XSA8LSBjKDMuMywtMyw0LC00LDUsLTUsNCwtNCwgNSwgLTUpCmBgYAoK0J/RgNC40LzQtdC90LjQvCDRgdC60L7Qu9GM0LfRj9GJ0YPRjiDQvNC10LTQuNCw0L3RgyBjINC80LDQu9C10L3RjNC60LjQvCDQvtC60L3QvtC8LgpgYGB7cn0KICBwbG90KHRlbXAudy5vdXRsaWVycykKICB0ZW1wLm1lZCA8LSBydW5tZWQodGVtcC53Lm91dGxpZXJzLCAzKQogIGxpbmVzKHRzKHRlbXAubWVkLCBzdGFydCA9IDE4ODAsIGZyZXF1ZW5jeSA9IDEpICwgY29sPSdyZWQnLCB0eXBlPSdsJykKYGBgCtCY0LfQsdCw0LLQuNC70LjRgdGMINC+0YIg0LDRg9GC0LvQsNC10YDQvtCyLgoKCiMj0KDQsNC30L3QvtGB0YLRjCDQv9C10YDQstC+0LPQviDQv9C+0YDRj9C00LrQsCAKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NX0KZGYgPC0gZGlmZih1aykKaC5kZiA8LSBjKC0xLDEpCnBsb3QoZGYsIHR5cGU9J2wnLCBtYWluPSdkaWZmZXJlbmNlJykKcGFyKG1mcm93PWMoMSwyKSkKc3AuaW5pdGlhbCA8LSBzcGVjLnBncmFtKHVrLCBkZXRyZW5kID0gRkFMU0UsIGZhc3QgPSBGQUxTRSwgbG9nPSdubycsIHRhcGVyPTAsIHhheHQgPSAnbicpCmF4aXMoMSwgYXQgPSBjKDAsMSwyLDMsNCw1LDYpLCBsYWJlbHMgPSBjKCcwJywgJzEvMTInLCAnMi8xMicsICczLzEyJywgJzQvMTInLCAnNS8xMicsICc2LzEyJykpCnNwLmRmIDwtIHNwZWMucGdyYW0obmEub21pdChkZiksIGRldHJlbmQgPSBGQUxTRSwgZmFzdCA9IEZBTFNFLCBsb2c9J25vJywgdGFwZXI9MCwgeGF4dCA9ICduJykKYXhpcygxLCBhdCA9IGMoMCwxLDIsMyw0LDUsNiksIGxhYmVscyA9IGMoJzAnLCAnMS8xMicsICcyLzEyJywgJzMvMTInLCAnNC8xMicsICc1LzEyJywgJzYvMTInKSkKcGFyKG1mcm93PWMoMSwxKSkKZnIuZGYgPC0gZnJlcXVlbmN5UmVzcG9uc2UoaC5kZiwgc3AuZGYkZnJlcS8xMikKcGxvdCh4ID0gc3AuZGYkZnJlcSwgeSA9IGZyLmRmLCB0eXBlID0gJ2wnLCB4bGFiID0gJ2ZyZXF1ZW5jeScsIHlsYWIgPSAncmVzcG9uc2UnLCB4YXh0ID0gJ24nKQpheGlzKDEsIGF0ID0gYygwLDEsMiwzLDQsNSw2KSwgbGFiZWxzID0gYygnMCcsICcxLzEyJywgJzIvMTInLCAnMy8xMicsICc0LzEyJywgJzUvMTInLCAnNi8xMicpKQpgYGAKCgoiSGlnaC1wYXNzIGZpbHRlciIgLS0g0L/RgNC+0L/Rg9GB0LrQsNC10YIg0LLRi9GB0L7QutC40LUg0YfQsNGB0YLQvtGC0YssINC90LjQt9C60LjQtSDRg9Cx0LjRgNCw0LXRgi4KCtCf0L7Rh9C10LzRgyDQv9C10YDQtdGF0L7QtCDQuiDRgNCw0LfQvdC+0YHRgtGP0Lwg0Y3RgtC+INGF0L7RgNC+0YjQvj8KCiog0JXRgdC70Lgg0LzQvtC00LXQu9GMINC90LDRiNC10LPQviDRgNGP0LTQsCDQuNC80LXQtdGCINCy0LjQtCAkeF90ID0gXG11X3QgKyB5X3QkLCDQs9C00LUgJFxtdV90JCAtLSDRgtGA0LXQvdC0LCAkeV90JCAtLSDRgdGC0LDRhtC40L7QvdCw0YDQvdGL0Lkg0L/RgNC+0YbQtdGB0YEsINGC0L4g0L/RgNC4INC/0LXRgNC10YXQvtC00LUg0Log0YDQsNC30L3QvtGB0YLRj9C8INC/0L7Qu9GD0YfQuNC8INGB0YLQsNGG0LjQvtC90LDRgNC90YvQuSDRgNGP0LQsINC+0YHQvtCx0LXQvdC90L4sINC10YHQu9C4INGC0YDQtdC90LQg0YTQuNC60YHQuNGA0L7QstCw0L0gKNC90LDQv9GA0LjQvNC10YAsINC70LjQvdC10LnQvdGL0LkpCgoqINCj0LLQtdC70LjRh9C40LLQtdC8INCy0LrQu9Cw0LQg0LLRi9GB0L7QutC40YUg0YfQsNGB0YLQvtGCLiDQndCw0L/RgNC40LzQtdGALCDQu9C10LPRh9C1INC30LDQvNC10YLQuNGC0Ywg0YHQtdC30L7QvdC90L7RgdGC0YwsINC60LDQuiDQvdCwINC/0LXRgNC40L7QtNC+0LPRgNCw0LzQvNC1INCy0YvRiNC1LgoKKiDQo9Cx0LXRgNC10Lwg0LvQuNC90LXQudC90YvQuSDRgtGA0LXQvdC0ICjQtdGB0LvQuCDQv9C10YDQtdC50LTQtdC8INC6INGA0LDQt9C90L7RgdGC0Y/QvCDQstGC0L7RgNC+0LPQviDQv9C+0YDRj9C00LrQsCwg0YLQviDQutCy0LDQtNGA0LDRgtC40YfQvdGL0Lkg0Lgg0YIu0LQuKQoK0JzQuNC90YPRgdGLCgoqINCj0LLQtdC70LjRh9C40LLQsNC10Lwg0LLQutC70LDQtCDRiNGD0LzQsC4g0J3QsNC/0YDQuNC80LXRgCwg0L3QsCDQv9C10YDQuNC+0LTQvtCz0YDQsNC80LzQtSDQstGL0YjQtSDQvdC1INGP0YHQvdC+INC+0YLQvdC+0YHQuNGC0Ywg0LvQuCDRgdC40L3Rg9GBINGBINGH0LDRgdGC0L7RgtC+0Lkg0YfRg9GC0Ywg0LHQvtC70YzRiNC1IDQvMTIg0Log0YHQtdC30L7QvdC90L7RgdGC0Lgg0LjQu9C4INGI0YPQvNGDLgoKCgoj0KHQs9C70LDQttC40LLQsNC90LjQtSDQuCDQstGL0LTQtdC70LXQvdC40LUg0YLRgNC10L3QtNCwINGBINC/0L7QvNC+0YnRjNGOINGA0LXQs9GA0LXRgdGB0LjQuAojI9Cb0LjQvdC10LnQvdCw0Y8g0YDQtdCz0YDQtdGB0YHQuNGPCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTV9CmZpdCA8LSBsbShkZi51ayRFWFAgfiBkZi51ayREQVRFLCBkZi51aykKcGxvdChkZi51aywgdHlwZT0nbCcpCmFibGluZShmaXQsIGNvbD0ncmVkJykKcGVyaW9kb2dyYW1CdWlsZGVyKGRmLnVrJEVYUCwgZml0JGZpdHRlZC52YWx1ZXMpCnBsb3QoZml0JHJlc2lkdWFscywgdHlwZT0nbCcpCmBgYAoKIyPQn9C+0LvQuNC90L7QvNC40LDQu9GM0L3QsNGPINGA0LXQs9GA0LXRgdGB0LjRjwpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTV9CmNzIDwtIGNvcygyKnBpKigxOmxlbmd0aCh1aykpLzEyKQpzbiA8LSBzaW4oMipwaSooMTpsZW5ndGgodWspKS8xMikKCmZpdCA8LSBsbShFWFAgfiBzdGF0czo6cG9seShkZi51ayREQVRFLCAxMCkKICAgICAgICAgICAgICAgICAgLCBkZi51aykKcGxvdChkZi51aywgdHlwZT0nbCcsIHlsYWI9IkVYUCIpCmxpbmVzKHk9IGZpdHRlZChmaXQpLCB4PSBkZi51ayREQVRFLCBjb2w9J3JlZCcpCnBsb3QoZml0JHJlc2lkdWFscywgdHlwZT0nbCcpCnBlcmlvZG9ncmFtQnVpbGRlcihkZi51ayRFWFAsIGZpdCRmaXR0ZWQudmFsdWVzKQpgYGAKCiMjS2VybmVsIFNtb290aGluZyAoa2VybmVsIHJlZ3Jlc3Npb24pCgpLZXJuZWwgU21vb3RoaW5nIC0tINGB0LrQvtC70YzQt9GP0YnQtdC1INGB0YDQtdC00L3QtdC1LCDQsiDQutC+0YLQvtGA0L7QvCDQuNGB0L/QvtC70YzQt9GD0LXRgtGB0Y8g0LLQtdGB0L7QstCw0Y8g0YTRg9C90LrRhtC40Y8gKGtlcm5lbCkuCgpD0YfQuNGC0LDQtdC8LCDRh9GC0L4g0L3QsNGIINGA0Y/QtCDQuNC80LXQtdGCINCy0LjQtDoKXGJlZ2lue2FsaWduKn0KICB4X3QgPSBmX3QgKyB5X3QsClxlbmR7YWxpZ24qfQrQs9C00LUgJGZfdCQgLS0g0L3QtdC60L7RgtC+0YDQsNGPINCz0LvQsNC00LrQsNGPINGE0YPQvdC60YbQuNGPLCAkeV90JCAtLSDRgdGC0LDRhtC40L7QvdCw0YDQvdGL0Lkg0L/RgNC+0YbQtdGB0YEuINCi0L7Qs9C00LAgClxiZWdpbnthbGlnbip9Clx3aWRlaGF0e2Z9X3QgPSBcc3VtX3tpID0gMX1ee259d19pKHQpeF9pLApcZW5ke2FsaWduKn0K0LPQtNC1ClxiZWdpbnthbGlnbip9CndfaSh0KSA9IEsoXGZyYWN7dC1pfXtifSkgLyBcc3VtX3tqID0gMX1ee259SyhcZnJhY3t0LWp9e2J9KS4KXGVuZHthbGlnbip9CgrQntCx0YvRh9C90L4gJEsoeikgPSBcZnJhY3sxfXtcc3FydHsyXHBpfX0gXGV4cCgtel4yIC8gMikkLgoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD01fQpwbG90KHVrLCB0eXBlPSdsJywgeWxhYj0iRVhQIikKdHJlbmQuc20gPC0ga3Ntb290aCh0aW1lKHVrKSwgdWssICdub3JtYWwnLCBiYW5kd2lkdGggPSAyKQpsaW5lcyh0cmVuZC5zbSwgY29sPSdyZWQnKQoKcGxvdCh1ayAtIHRyZW5kLnNtJHkpCnBlcmlvZG9ncmFtQnVpbGRlcih1aywgdHJlbmQuc20keSkKYGBgCgojI05lYXJlc3QgTmVpZ2hib3IgUmVncmVzc2lvbgoK0KHRgtGA0L7QuNC8INC70LjQvdC10LnQvdGD0Y4g0YDQtdCz0YDQtdGB0YHQuNGOINC90LAgJGskINCx0LvQuNC20LDQudGI0LjRhSDRgdC+0YHQtdC00LXQuS4g0KIu0LUuINC/0YDQtdC00YHQutCw0LfRi9Cy0LDQtdC8ICR4X3QkINC/0L4gJFx7eF97dC1rLzJ9LFxsZG90cywgeF90LFxsZG90cywgeF97dCtrLzJ9XH0kLgoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD01fQpwbG90KHVrLCB0eXBlPSdsJywgeWxhYj0ibSDCoyIpCm5laWdoLnQgPC0ga25uLnJlZyh0cmFpbiA9IHRpbWUodWspLCB5ID0gdWssIGsgPSAyNCkkcHJlZCNzdXBzbXUodGltZSh1ayksIHVrLCBzcGFuID0gLjMpCm5laWdoLnQgPC0gdHMobmVpZ2gudCwgc3RhcnQgPSBjKDE5ODAsIDEpLCBmcmVxdWVuY3kgPSAxMikKbGluZXMobmVpZ2gudCwgY29sPSdyZWQnKQoKCnBsb3QodWsgLSBuZWlnaC50KQpwZXJpb2RvZ3JhbUJ1aWxkZXIodWssIG5laWdoLnQpCmBgYAoKIyPQodGA0LDQstC90LXQvdC40LUg0LzQtdGC0L7QtNC+0LIKCiog0JvQuNC90LXQudC90LDRjyDRgNC10LPRgNC10YHRgdC40Y8gLS0g0L/QvtC00YXQvtC00LjRgiDRgtC+0LvRjNC60L4g0LTQu9GPINCy0YvQtNC10LvQtdC90LjRjyDQu9C40L3QtdC50L3QvtCz0L4g0YLRgNC10L3QtNCwCiog0J/QvtC70LjQvdC+0LzQuNCw0LvRjNC90LDRjyDRgNC10LPRgNC10YHRgdC40Y8gLS0g0L3QtSDQv9C+0LTRhdC+0LTQuNGCINC00LvRjyDQv9GA0L7Qs9C90L7Qt9C40YDQvtCy0LDQvdC40Y8KKiDQn9Cw0YDQsNC80LXRgtGA0LjRh9C10YHQutC40LUg0LzQtdGC0L7QtNGLINC/0LvQvtGF0L4g0YHRgNCw0LHQvtGC0LDRjtGCLCDQtdGB0LvQuCDQvdC1INC/0YDQtdC00L/QvtC70LDQs9Cw0LXRgtGB0Y8sINGH0YLQviDRgtGA0LXQvdC0IC0tINCy0YHQtdCz0LTQsCDQvtC00L3QsCDQuCDRgtCwINC20LUg0YTRg9C90LrRhtC40Y8gCiogTmVhcmVzdCBOZWlnaGJvciBSZWdyZXNzaW9uLCBLZXJuZWwgU21vb3RoaW5nIC0tINC90LXQv9Cw0YDQsNC80LXRgtGA0LjRh9C10YHQutC40LUg0LzQtdGC0L7QtNGLLCDQvdC10YIg0L7Qs9GA0LDQvdC40YfQtdC90L3QvtGB0YLQuCDQvNC+0LTQtdC70YzRjgoK0JTQu9GPINCy0YvQtNC10LvQtdC90LjRjyDRgtGA0LXQvdC00LAg0Y8g0LHRiyDQstGL0LHRgNCw0LsgTmVhcmVzdCBOZWlnaGJvciBSZWdyZXNzaW9uINC40LvQuCBLZXJuZWwgU21vb3RoaW5nLgoKI1NlYXNvbmFsIERlY29tcG9zaXRpb24gCgoK0KXQvtGC0LjQvCDQv9GA0LXQtNGB0YLQsNCy0LjRgtGMINGA0Y/QtCDQsiDQstC40LTQtSAkWF9uID0gVF9uICsgU19uICsgTl9uJC4KCtCR0YPQtNC10Lwg0LTQtdC70LDRgtGMINCy0YHQtSDQtNC70Y8g0LvQvtCz0LDRgNC40YTQvNC40YDQvtCy0LDQvdC90L7Qs9C+INGA0Y/QtNCwLCDRgtCw0Log0LrQsNC6INC+0L0g0L/QvtGF0L7QtiDQvdCwINC70LjQvdC10LnQvdGD0Y4g0LzQvtC00LXQu9GMICjQsNC80L/Qu9C40YLRg9C00LAg0L/RgNC40LzQtdGA0L3QviDQvtC00LjQvdCw0LrQvtCy0LApLiDQnNC+0LbQvdC+INC30LDQvNC10L3QuNGC0Ywg0LTQsNC70LXQtSDRgdC70L7QttC10L3QuNC1INC90LAg0YPQvNC90L7QttC10L3QuNC1LCDRgNCw0LfQvdC+0YHRgtGMINC90LAg0LTQtdC70LXQvdC40LUg0Lgg0L/QvtC70YPRh9C40YLRjCDQsNC70LPQvtGA0LjRgtC8INC00LvRjyDQvNGD0LvRjNGC0LjQv9C70LjQutCw0YLQuNCy0L3QvtC5INC80L7QtNC10LvQuC4KCtCl0L7RgNC+0YjQtdC1INC+0L/QuNGB0LDQvdC40LUg0LDQu9Cz0L7RgNC40YLQvNCwINC90LDRiNC10Lsg0LfQtNC10YHRjDoKaHR0cDovL3d3dy5hYnMuZ292LmF1L3dlYnNpdGVkYnMvZDMzMTAxMTQubnNmLzUxYzlhM2QzNmVkZmQwZGZjYTI1NmFjYjAwMTE4NDA0L2M4OTBhYThlNjU5NTczOTdjYTI1NmNlMTAwMThjOWQ4IW9wZW5kb2N1bWVudAoKKiDQndCw0YfQsNC70YzQvdCw0Y8g0L7RhtC10L3QutCwINGC0YDQtdC90LTQsC4g0J/RgNC40LzQtdC90Y/QtdC8INGB0LrQvtC70YzQt9GP0YnQtdC1INGB0YDQtdC00L3QtdC1INGBINC00LvQuNC90L7QuSDQvtC60L3QsCBULCDQsiDQvdCw0YjQtdC8INGB0LvRg9GH0LUg0LrRgNCw0YLQvdC+0LkgMTIuCgoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD01fQpUMSA8LSBNb3ZBdmcobG9nKHVrKSwgMjQpClNOMSA8LSBsb2codWspIC0gVDEKcGVyaW9kb2dyYW1CdWlsZGVyKGxvZyh1ayksIFQxKQpgYGAKCiog0J/QvtC70YPRh9C40LvQuCDRgNGP0LQg0LIg0LLQuNC00LUgJFhfbiA9IFx3aWRldGlsZGV7VH1fbiArIFx3aWRldGlsZGV7U19uICsgTl9ufSQKCiogINCe0YbQtdC90LrQsCDRgdC10LfQvtC90L3QvtC5INC60L7QvNC/0L7QvdC10L3RgtGLLiDQodCz0LvQsNC20LjQstCw0LXQvCAkXHdpZGV0aWxkZXtTX24gKyBOX259JCDRgSDQvNCw0LvQtdC90YzQutC40Lwg0L7QutC90L7QvC4g0J/QvtC70YPRh9Cw0LXQvCAkXHdpZGV0aWxkZXtTX24gKyBOX259ID0gXHdpZGV0aWxkZXtTfV9uICsgXHdpZGV0aWxkZXtOfV9uJC4gCgoqINCj0LHQuNGA0LDQtdC8INC/0L7Qu9GD0YfQtdC90L3Rg9GOINGB0LXQt9C+0L3QvdC+0YHRgtGMINC40Lcg0LjRgdGF0L7QtNC90L7Qs9C+INGA0Y/QtNCwLCDQv9C+0LvRg9GH0LDQtdC8INC+0YbQtdC90LrRgyDQuNGB0L/RgNCw0LLQu9C10L3QvdC+0LPQviDRgNGP0LTQsCAoYWRqdXN0ZWQpLgoKCmBgYHtyfQpTMSA8LSBNb3ZBdmcoU04xLCAyKQpBREoxIDwtIGxvZyh1aykgLSBTMQpwZXJpb2RvZ3JhbUJ1aWxkZXIoU04xLCBTMSkKYGBgCiog0KPQu9GD0YfRiNC10L3QvdCw0Y8g0L7RhtC10L3QutCwINGC0YDQtdC90LTQsC4g0J/RgNC40LzQtdC90Y/QtdC8INGB0LrQvtC70YzQt9GP0YnQtdC1INGB0YDQtdC00L3QtdC1INGBINCx0L7Qu9GM0YjQuNC8INC+0LrQvdC+0Lwg0Log0LjRgdC/0YDQsNCy0LvQtdC90L3QvtC80YMg0YDRj9C00YMgJFhfbiAtIFx3aWRldGlsZGV7U31fbiQsINC/0L7Qu9GD0YfQsNC10LwgJFx3aWRldGlsZGV7XHdpZGV0aWxkZXtUfX1fbiArICBcd2lkZXRpbGRle1x3aWRldGlsZGV7Tn19X24kCgoqINCe0YLRgdGO0LTQsCDQstGC0L7RgNC+0Lkg0YDQsNC3INC+0YbQtdC90LjQstCw0LXQvCAkXHdpZGV0aWxkZXtcd2lkZXRpbGRle1NfbiArIE5fbn19ID0gWF9uIC0gXHdpZGV0aWxkZXtcd2lkZXRpbGRle1R9fV9uJAoKYGBge3J9ClQyIDwtIE1vdkF2ZyhBREoxLCAyNCkKU04yIDwtIGxvZyh1aykgLSBUMgpwZXJpb2RvZ3JhbUJ1aWxkZXIoQURKMSwgVDIpCmBgYAoKKiDQn9GA0LjQvNC10L3Rj9C10Lwg0YHQutC+0LvRjNC30Y/RidC10LUg0YHRgNC10LTQvdC10LUg0YEg0LzQsNC70LXQvdGM0LrQuNC8INC+0LrQvdC+0Lwg0LogJFx3aWRldGlsZGV7XHdpZGV0aWxkZXtTX24gKyBOX259fSQsINC/0L7Qu9GD0YfQsNC10LwgJFx3aWRldGlsZGV7XHdpZGV0aWxkZXtTfX1fbiArICBcd2lkZXRpbGRle1x3aWRldGlsZGV7XHdpZGV0aWxkZXtOfX19X24kLiBD0L3QvtCy0LAg0L7RhtC10L3QuNCy0LDQtdC8INC40YHQv9GA0LDQstC70LXQvdC90YvQuSDRgNGP0LQKYGBge3J9ClMyIDwtIE1vdkF2ZyhTTjIsIDIpCkFESjIgPC0gbG9nKHVrKSAtIFMyCnBlcmlvZG9ncmFtQnVpbGRlcihTTjIsIFMyKQpgYGAKCiog0KTQuNC90LDQu9GM0L3QsNGPINC+0YbQtdC90LrQsCDRgtGA0LXQvdC00LAg0Lgg0YjRg9C80LAKCmBgYHtyfQpUMyA8LSBNb3ZBdmcoQURKMiwgMjQpCk4xIDwtIEFESjIgLSBUMwpwZXJpb2RvZ3JhbUJ1aWxkZXIoQURKMiwgVDMpCmBgYAoKCgoqINCf0L7Qu9GD0YfQuNC70LggJFhfbiA9IFx3aWRldGlsZGV7XHdpZGV0aWxkZXtUfX1fbiArIFx3aWRldGlsZGV7XHdpZGV0aWxkZXtTfX1fbiArICBcd2lkZXRpbGRle1x3aWRldGlsZGV7XHdpZGV0aWxkZXtOfX19X24kCgpgYGB7ciwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTh9CnBhcihtZnJvdz1jKDQsMSkpCnBsb3QobG9nKHVrKSwgdHlwZSA9ICdsJywgeWxhYj0nT3JpZ2luYWwnKQpwbG90KFQzLCB0eXBlPSdsJywgeWxhYj0nVHJlbmQnKQpwbG90KFMyLCB0eXBlPSdsJywgeWxhYiA9ICdTZWFzb25hbCBDb21wb25lbnQnKQpwbG90KE4xLCB0eXBlPSdsJywgeWxhYj0nTm9pc2UnKQpgYGAKCmBgYHtyfQphY2YoTjEsIGxhZy5tYXggPSAxMDApCmBgYArQqNGD0Lwg0LHQtdC70YvQvCDQvdC1INC/0L7Qu9GD0YfQuNC70YHRjy4g0JrQsNC6INCy0LjQtNC90L4g0LjQtyDQv9C+0YHQu9C10LTQvdC40YUg0L/QtdGA0LjQvtC00L7Qs9GA0LDQvNC8LCDQvNC90L7Qs9C+INC/0LXRgNC40L7QtNC40YfQtdGB0LrQuNGFINC60L7QvNC/0L7QvdC10L3RgiDRgtCw0Log0Lgg0L3QtSDQstGL0LTQtdC70LjQu9C40YHRjCDQsiDRgdC10LfQvtC90L3Rg9GOINC60L7QvNC/0L7QvdC10L3RgtGDLgoKCiNTVEwgKExPRVNTKQoKIyPQkNC70LPQvtGA0LjRgtC8CgojIyNJbm5lciBsb29wCtCf0L7QstGC0L7RgNGP0LXQvCAkbl97KGkpfSQg0YDQsNC3LgoKKiBEZXRyZW5kaW5nCgokWV9uIC0gVF9uXnsoayl9JCwgJFRfbl57KDApfSA9IDAkLCAkWV9uJCAtLSDQuNGB0YXQvtC00L3Ri9C5INGA0Y/QtCwgJFRfbl57KGspfSQgLS0g0L7RhtC10L3QutCwINGC0YDQtdC90LTQsCDQvdCwINGI0LDQs9C1IGsg0LLQvdGD0YLRgNC10L3QvdC10LPQviDRhtC40LrQu9CwCgoqIEN5Y2xlLXN1YnNlcmllcyBzbW9vdGhpbmcKCtCa0LDQttC00YvQuSDQv9C10YDQuNC+0LQg0LTQu9C40L3RiyAkbl97KHApfSQg0YHQs9C70LDQttC40LLQsNC10YLRgdGPIExPRVNTKHEpLCAkcSA9IG5feyhzKX0sIGQgPSAxJCwg0LPQtNC1ICRkJCAtLSDRgdGC0LXQv9C10L3RjCDQv9C+0LvQuNC90L7QvNCwLCAkcSQgLS0g0YfQuNGB0LvQviDRgdC+0YHQtdC00LXQuS4KCtCa0YDQvtC80LUg0YLQvtCz0L4sINGB0YfQuNGC0LDQtdC8INGB0LPQu9Cw0LbQtdC90L3Ri9C1INC30L3QsNGH0LXQvdC40Y8g0LTQu9GPINC+0LTQvdC+0Lkg0YLQvtGH0LrQuCDQv9C10YDQtdC0INC90LDRh9Cw0LvQvtC8INC4INC+0LTQvdC+0Lkg0YLQvtGH0LrQuCDQv9C+0YHQu9C1INC60L7QvdGG0LAg0LrQsNC20LTQvtCz0L4g0L/QtdGA0LjQvtC00LAuINCt0YLQviDQvdGD0LbQvdC+INC00LvRjyDRgtC+0LPQviwg0YfRgtC+0LHRiyDQv9C+0YHQu9C1INC/0YDQuNC80LXQvdC10L3QuNGPINGB0LrQvtC70YzQt9GP0YnQuNGFINGB0YDQtdC00L3QuNGFINC90LAg0YHQu9C10LTRg9GO0YnQtdC8INGI0LDQs9C1LCDQvtGB0YLQsNC70L7RgdGMIE4g0YLQvtGH0LXQui4g0KLQviDQtdGB0YLRjCwg0YfRgtC+0LHRiyDQvNGLINC90LjRh9C10LPQviDQvdC1INC/0L7RgtC10YDRj9C70LguCgrQn9C+0LvRg9GH0LjQu9C4INGA0Y/QtCAkQ197bn1eeyhrICsgMSl9JCDRgdC+0LTQtdGA0LbQsNGJ0LjQuSAkTiArIDIqbl97KHApfSQg0YLQvtGH0LXQui4KCiogTG93LVBhc3MgRmlsdGVyaW5nIG9mIFNtb290aGVkIEN5Y2xlLVN1YnNlcmllcwoK0J/QvtGB0LvQtdC00L7QstCw0YLQtdC70YzQvdC+INC/0YDQuNC80LXQvdGP0LXQvCAyINGB0LrQvtC70YzQt9GP0YnQuNGFINGB0YDQtdC00L3QuNGFINGBINC00LvQuNC90L3QvtC5INC+0LrQvdCwICRuX3socCl9JC4KCtCf0YDQuNC80LXQvdGP0LXQvCDRgdC60L7Qu9GM0LfRj9GJ0LXQtSDRgdGA0LXQtNC90LXQtSDRgSDQtNC70LjQvdC90L7QuSDQvtC60L3QsCAzLgoK0J/RgNC40LzQtdC90Y/QtdC8IExPRVNTINGBINC/0LDRgNCw0LzQtdGC0YDQsNC80LggJHEgPSBuX3sobCl9LCBkID0gMSQuCgrQn9C+0LvRg9GH0LjQu9C4INGA0Y/QtCAkTF9uXnsoayArIDEpfSQKCiogRGV0cmVuZGluZyBvZiBTbW9vdGhlZCBDeWNsZS1TdWJzZXJpZXMKCtCh0YfQuNGC0LDQtdC8INGA0Y/QtCAkU19uXnsoayArIDEpfSA9IENfbl57KGsgKyAxKX0gLSBMX25eeyhrICsgMSl9JC4KCiogRGVzZWFzb25hbGl6aW5nCgrQodGH0LjRgtCw0LXQvCDRgNGP0LQgJFlfbiAtICBTX25eeyhrICsgMSl9JC4KCiogVHJlbmQgU21vb3RoaW5nIAoK0KDRj9C0INCx0LXQtyDRgdC10LfQvtC90L3QvtGB0YLQuCwg0LLRi9GH0LjRgdC70LXQvdC90YvQuSDQvdCwINC/0YDQtdC00YvQtNGD0YnQtdC8INGI0LDQs9C1LCDRgdCz0LvQsNC20LjQstCw0LXRgtGB0Y8gTE9FU1Mg0YEgJHEgPSBuX3sodCl9LCBkID0gMSQuCgrQn9C+0LvRg9GH0LjQu9C4INC+0YbQtdC90LrRgyDRgtGA0LXQvdC00LAgJFRfbl57KGsgKyAxKX0kCgojIyNPdXRlciBMb29wCtCf0L7QstGC0L7RgNGP0LXQvCAkbl97KG8pfSQg0YDQsNC3LgoK0J/Rg9GB0YLRjCDQvNGLINC/0L7Qu9GD0YfQuNC70Lgg0L7RhtC10L3QutC4ICRUX24sIFNfbiQgYyDQv9C+0LzQvtGJ0YzRjiDQstC90YPRgtGA0LXQvdC90LXQs9C+INGG0LjQutC70LAsINGC0L7Qs9C00LAg0L7RgdGC0LDRgtC+0LogJFJfbiA9IFlfbiAtIFRfbiAtIFNfbiQuCgrQntC/0YDQtdC00LXQu9C40Lwg0LLQtdGB0LAsINC60L7RgtC+0YDRi9C1INC/0L7Qt9Cy0L7Qu9GP0YIg0L3QsNC8INC40YHQutC70Y7Rh9C40YLRjCDQsNGD0YLQu9Cw0LXRgNGLLiAKCiRoID0gNiBtZWRpYW4ofFJfbnwpJCwg0YLQvtCz0LTQsCDQstC10YEg0LIg0YLQvtGH0LrQtSAkbiQgJFxyaG9fbiA9IEIofFJfbnwvaCkkLCDQs9C00LUgJEIkLdCx0LjQutCy0LDQtNGA0LDRgtC90LDRjyDQstC10YHQvtCy0LDRjyDRhNGD0L3QutGG0LjRjy4KCtCd0LAg0YHQu9C10LTRg9GO0YnQtdC5INC40YLQtdGA0LDRhtC40Lgg0LLQviDQstC90YPRgtGA0LXQvdC90LXQvCDRhtC40LrQu9C1LCDQvdCwINGI0LDQs9Cw0YUgMiDQuCA2LCDQstC10YHQsCwg0LrQvtGC0L7RgNGL0LUg0L/RgNC40YHQstCw0LjQstCw0Y7RgtGB0Y8g0YLQvtGH0LrQsNC8INCyIExPRVNTINGD0LzQvdC+0LbQuNC8INC90LAg0YHQvtC+0YLQstC10YLRgdGC0LLRg9GO0YnQuNC1ICRccmhvX24kLgoKIyMj0J/QsNGA0LDQvNC10YLRgNGLCgrQotCw0LrQuNC8INC+0LHRgNCw0LfQvtC8LCBTVEwg0LjQvNC10LXRgiA2INC/0LDRgNCw0LzQtdGC0YDQvtCyOgoKKiAkbl97KHApfSQgLS0g0LrQvtC70LjRh9C10YHRgtCy0L4g0L3QsNCx0LvRjtC00LXQvdC40Lkg0LIg0LrQsNC20LTQvtC8INGG0LjQutC70LUg0YHQtdC30L7QvdC90L7QuSDQutC+0LzQv9C+0L3QtdC90YLRiyAo0L/QtdGA0LjQvtC0KSAKKiAkbl97KGkpfSQgKGlubmVyKSAtLSDRh9C40YHQu9C+INC40YLQtdGA0LDRhtC40Lkg0LLQvdGD0YLRgNC10L3QvdC10LPQviDRhtC40LrQu9CwCiogJG5feyhvKX0kIChvdXRlcikgLS0g0YfQuNGB0LvQviDQuNGC0LXRgNCw0YbQuNC5INCy0L3QtdGI0L3QtdCz0L4g0YbQuNC60LvQsAoqICRuX3sobCl9JCAobC53aW5kb3cpIC0tINGB0LPQu9Cw0LbQuNCy0LDRjtGJ0LjQuSDQv9Cw0YDQsNC80LXRgtGAINC00LvRjyBsb3ctcGFzcyDRhNC40LvRjNGC0YDQsCAo0LrQvtC70LjRh9C10YHRgtCy0L4g0YHQvtGB0LXQtNC10Lkg0LIgTE9FU1MpCiogJG5feyh0KX0kICh0LndpbmRvdykgLS0g0YHQs9C70LDQttC40LLQsNGO0YnQuNC5INC/0LDRgNCw0LzQtdGC0YAg0LTQu9GPINGC0YDQtdC90LTQsCAo0LrQvtC70LjRh9C10YHRgtCy0L4g0YHQvtGB0LXQtNC10Lkg0LIgTE9FU1MpCiogJG5feyhzKX0kIChzLndpbmRvdykgLS0g0YHQs9C70LDQttC40LLQsNGO0YnQuNC5INC/0LDRgNCw0LzQtdGC0YAg0YHQtdC30L7QvdC90L7RgdGC0LggKNC60L7Qu9C40YfQtdGB0YLQstC+INGB0L7RgdC10LTQtdC5INCyIExPRVNTKSAKCtCU0YDRg9Cz0LjQtSDQv9Cw0YDQsNC80LDQtdGC0YDRiywg0LTQvtGB0YLRg9C/0L3Ri9C1INCyINGE0YPQvdC60YbQuNC4CgoqIHQocyxsKS5kZWdyZWUgLS0g0YHRgtC10L/QtdC90Ywg0L/QvtC70LjQvdC+0LzQsCDQsiBMT0VTUyDQtNC70Y8g0YHQvtC+0YLQstC10YLRgdGC0LLRg9GO0YnQuNGFINC60L7QvNC/0L7QvdC10L3RgiAoMCDQuNC70LggMSkKCiMj0JjRgdC/0L7Qu9GM0LfQvtCy0LDQvdC40LUKCtCS0YvQsdC10YDQtdC8INGB0LvQtdC00YPRjtGJ0LjQtSDQv9Cw0YDQsNC80LXRgtGA0YsKCiogcy53aW5kb3cgPSAxMyDRgtCw0Log0LrQsNC6INGDINC90LDRgSDQs9C+0LTQvtCy0LDRjyDQv9C10YDQuNC+0LTQuNGH0L3QvtGB0YLRjCwg0Lgg0L/QsNGA0LDQvNC10YLRgCDQtNC+0LvQttC10L0g0LHRi9GC0Ywg0L3QtdGH0LXRgtC90YvQvAoqIGwud2luZG93ID0gMTMg0YDQtdC60L7QvNC10L3QtNGD0LXRgtGB0Y8g0LHRgNCw0YLRjCDQsdC70LjQttCw0LnRiNC40Lwg0L3QtdGH0LXRgtC90YvQvCDQuiAkbl97KHApfSQKKiBvdXRlciA9IDAsINCw0YPRgtC70LDQtdGA0L7QsiDQvdC10YIKKiBpbm5lciA9IDIsINGD0YLQstC10YDQttC00LDQtdGC0YHRjywg0YfRgtC+INC00L7RgdGC0LDRgtC+0YfQvdC+INC4INC+0LTQvdC+0Lkg0LjRgtC10YDQsNGG0LjQuCDQstC90YPRgtGA0LXQvdC90LXQs9C+INGG0LjQutC70LAsINC90L4g0LTQu9GPINC70YPRh9GI0LXQuSDRgdGF0L7QtNC40LzQvtGB0YLQuCDRgNC10LrQvtC80LXQvdC00YPRjtGCIDIKKiB0LndpbmRvdyA9IDIzLCDRgNC10LrQvtC80LXQvdC00YPQtdGC0YHRjyDQsdGA0LDRgtGMICRuX3sodCl9ID0gWzEuNSBuX3socCl9LygxIC0gMS41L25feyhzKX0pXV97b2RkfSQKCgoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KdWsuc3RsIDwtIHN0bCh1aywgcy53aW5kb3cgPSAxMywgbC53aW5kb3cgPSAxMywgb3V0ZXIgPSAwLCBpbm5lciA9IDIsIHQud2luZG93ID0gMjMpCnBsb3QodWsuc3RsKQpgYGAKCmBgYHtyfQphY2YodWsuc3RsJHRpbWUuc2VyaWVzWywzXSwgbGFnLm1heCA9IDEwMCkKYGBgCgoKIyPQodGC0LDQsdC40LvQuNC30LDRhtC40Y8g0LTQuNGB0L/QtdGA0YHQuNC4CgrQntGB0YLQsNGC0L7QuiDQv9C+0YHQu9C1IHN0bApgYGB7cn0KcmVtIDwtIHVrLnN0bCR0aW1lLnNlcmllc1ssM10KcGxvdChyZW0pCmBgYAoK0J/RgNC+0LvQvtCz0L7RgNC40YTQvNC40YDRg9C10Lwg0LjRgdGF0L7QtNC90YvQuSDRgNGP0LQg0Lgg0YHQvdC+0LLQsCDQv9C+0YHQvNC+0YLRgNC40Lwg0L3QsCDQvtGB0YLQsNGC0L7QuiDQv9C+0YHQu9C1INCy0YvQtNC10LvQtdC90LjRjyDRgtGA0LXQvdC00LAuCmBgYHtyfQp1ay5sb2cgPC0gbG9nKHVrKQp1ay5sb2cuc3RsIDwtIHN0bCh1ay5sb2csIHMud2luZG93ID0gMTMsIGwud2luZG93ID0gMTMsIG91dGVyID0gMCwgaW5uZXIgPSAyLCB0LndpbmRvdyA9IDIzKQpsb2cucmVtIDwtIHVrLmxvZy5zdGwkdGltZS5zZXJpZXNbLDNdCnBsb3QobG9nLnJlbSkKYGBgCgrQntGG0LXQvdC40Lwg0LTQuNGB0L/QtdGA0YHQuNGOCgrQmNC00LXRjyAKKiDQktGL0LTQtdC70LjQsiDRgtGA0LXQvdC0LCDQv9C+0LvRg9GH0LjQu9C4INGI0YPQvCDRgSDQvdC10LrQvtGC0L7RgNC+0Lkg0LTQuNGB0L/QtdGA0YHQuNC10LkgJFx4aV9uID0gXHNpZ21hKG4pXGVwc2lsb25fbiQKCiog0JLRi9C00LXQu9C40YLRjCDRgtGA0LXQvdC0INGDICRceGlfbl4yID0gXHNpZ21hKG4pXjJcZXBzaWxvbl9uXjIkIC0tINCy0YHQtSDRgNCw0LLQvdC+LCDRh9GC0L4g0L3QsNC50YLQuCDRgdGA0LXQtNC90LXQtSAkXG1hdGhiZntFfVx4aV9uXjIgPSBcc2lnbWEobileMiQKCtCS0L7Qt9Cy0LXQtNC10Lwg0L7RgdGC0LDRgtC+0Log0LIg0LrQstCw0LTRgNCw0YIg0Lgg0LLRi9C00LXQu9C40Lwg0YLRgNC10L3QtCDRgdC60L7Qu9GM0LfRj9GJ0LjQvCDRgdGA0LXQtNC90LjQvApgYGB7cn0KZGlmLnNxciA8LSB0cyhsb2cucmVtXjIpCnBsb3QoZGlmLnNxciwgdHlwZSA9ICdsJykKc2lnbWEubi5zcXIgPC0gTW92QXZnKGRpZi5zcXIsIDI0KQpsaW5lcyhzaWdtYS5uLnNxciwgY29sPSdyZWQnKQpsZWdlbmQoInRvcGxlZnQiLCBjKCJSZW1eMiIsICJzaWdtYShuKV4yIiksIGx0eT1jKDEsMSksIGx3ZD1jKDIuNSwyLjUpLGNvbD1jKCJibGFjayIsInJlZCIpKQpgYGAKCtCf0L7RgdGC0YDQvtC40Lwg0L7Qs9C40LHQsNGO0YnRg9GOIApgYGB7cn0Kbm9pc2UgPC0gdHMobG9nLnJlbSAvIHNxcnQoc2lnbWEubi5zcXIpKQpwbG90KGxvZy5yZW0sIHR5cGUgPSAnbCcpCmxpbmVzKHRzKHNxcnQoc2lnbWEubi5zcXIpLCBzdGFydCA9IGMoMTk4MCwgMSksIGZyZXF1ZW5jeSA9IDEyKSwgY29sID0gJ2JsdWUnKQpsaW5lcyh0cygtc3FydChzaWdtYS5uLnNxciksIHN0YXJ0ID0gYygxOTgwLCAxKSwgZnJlcXVlbmN5ID0gMTIpLCBjb2wgPSAnYmx1ZScpCmBgYAoK0J7RhtC10L3QutCwINGI0YPQvNCwLCDQtdC1INC/0LXRgNC40L7QtNC+0LPRgNCw0LzQvNCwINC4INCw0LLRgtC+0LrQvtCy0LDRgNC40LDRhtC40L7QvdC90LDRjyDRhNGD0L3QutGG0LjRjwpgYGB7cn0KcGxvdChub2lzZSkKc3BlYy5wZ3JhbShuYS5vbWl0KG5vaXNlKSwgZGV0cmVuZCA9IEZBTFNFLCBmYXN0ID0gRkFMU0UsIGxvZz0nbm8nLCB0YXBlcj0wKQphY2Yobm9pc2UsIGxhZy5tYXggPSA1MCkKYGBg